Blogbody Rotating Header Image

Anemic domain model solved (without source weaving)

I am perplexed by the use of source code weaving and AOP in Spring 2.0 to solve the anemic domain model problem. I propose a better solution: a community-driven effort to standardize on an ObjectFactory API.

Let me give an example: in WebWork, there is an ObjectFactory that is responsible for the creation of any object. I do mean any object: actions, interceptors, results, domain objects that need to be initialized because they were null, etc. Anything. The default implementation simply looks up classes and calls newInstance().

WebWork provides a WebWorkSpringObjectFactory that tries a few things:

  • Look up the “class name” (it might just be a bean name in reality) in Spring and use that if it is exists.
  • If the bean doesn’t exist, ask Spring to create it and wire it using the automatic wiring rules you’ve specified in applicationContext.xml.

This means that my HTML forms can have parameters like “person.name” and my action can have an empty Person property. Since WebWork will automatically create the Person object using the registered ObjectFactory, my Person object will have a PersonService wired up to it automatically. Simple and easy.

Now I’m using iBatis (I love it, but that’s for a different entry). Unfortunately, iBatis doesn’t have an ObjectFactory concept. But if it did, I could plug the same implementation in and now objects created from a SELECT statement would also be wired up properly.

Ta-da! No source code weaving. No pre-compilation step. No AOP. Just simple agreement on a standard interface. Why can’t we all get together and do this?

PS: In the short term, simply putting some self-wiring code in the Person constructor can get you by. It’s one additional line of code per domain model, which I prefer much more over an invasive pre-compilation step.

Update: I decided to put up the simplest code possible to show you how you can have rich domain models without all crazy Spring 2.0 stuff. Just make your domain models extend Model (or place the same one-liner in each constructor):

public class Model {
public Model() {
SpringAutoWire.autoWire(this);
}
}

And SpringAutoWire looks like this (it has both a static method and is a definied as a listern in web.xml):

public class SpringAutoWire implements ServletContextListener {
private static AutowireCapableBeanFactory autoWiringBeanFactory;

public void contextInitialized(ServletContextEvent servletContextEvent) {
init(servletContextEvent.getServletContext());
}

public void contextDestroyed(ServletContextEvent servletContextEvent) {
// nothing needed
}

private static void init(ServletContext servletContext) {
WebApplicationContext webApplicationContext
= WebApplicationContextUtils.getWebApplicationContext(servletContext);
autoWiringBeanFactory = findAutoWiringBeanFactory(webApplicationContext);
}

public static void autoWire(Object o) {
autoWiringBeanFactory.autowireBeanProperties(o, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, false);
}

private static AutowireCapableBeanFactory findAutoWiringBeanFactory(ApplicationContext context) {
if (context instanceof AutowireCapableBeanFactory) {
// Check the context
return (AutowireCapableBeanFactory) context;
} else if (context instanceof ConfigurableApplicationContext) {
// Try and grab the beanFactory
return ((ConfigurableApplicationContext) context).getBeanFactory();
} else if (context.getParent() != null) {
// And if all else fails, try again with the parent context
return findAutoWiringBeanFactory(context.getParent());
}
return null;
}
}

13 Comments on “Anemic domain model solved (without source weaving)”

  1. #1 Matt Raible
    on Jan 30th, 2006 at 4:19 pm

    I like the idea. However, you have a class implementing a Servlet API interface in your model objects. Not exactly loose-coupling is it?

  2. #2 Patrick Lightbody
    on Jan 30th, 2006 at 4:26 pm

    Matt, you’re right – this is just a short term fix. The better fix I’m proposing is a standardized ObjectFactory for all projects to agree upon and use.

  3. #3 Matt Raible
    on Jan 30th, 2006 at 7:08 pm

    +1 to a standardized ObjectFactory. I love how WebWork will automatically instantiate null Objects (i.e. model objects on Actions) – whereas other frameworks leave that up to the programmer.

  4. #4 Patrick Lightbody
    on Jan 30th, 2006 at 7:37 pm

    Matt,
    Perhaps it is time for a new OpenSymphony project. The real win, however, will come from adoption by the major players (Hibernate, iBatis, WebWork, Tapestry, etc).

  5. #5 Jing Xue
    on Jan 30th, 2006 at 8:46 pm

    I think the idea is valid, but is it really practical? I mean, it might actually be easier to ask Sun to add overloading support to the ‘new’ operator, than to ask all the projects to support ObjectFactory, which is essentially an overloaded ‘new’. Right? 8-)

  6. #6 Patrick Lightbody
    on Jan 30th, 2006 at 9:12 pm

    Well, I don’t want all projects to support it – just the ones I use :)

  7. #7 Adrian Colyer
    on Jan 31st, 2006 at 5:56 am

    It seems unlikely that everyone will agree to a standard ObjectFactory for construction of an arbitrary object (and even if they did, there’s a ton of existing code out there that won’t be using it). For objects that aren’t created by a framework, I still want to be able to write e.g. “new Account()” in my code too.

    Explicitly adding a call to some wiring support class inside the constructor of a domain class is conceptually similar to what the @Configurable support in Spring with AspectJ does. Except that here you have to remember to put it in every constructor (or carefully chain constructor calls, in which case the wiring will probably happen before the constructors have finished executing, which may or may not matter depending on your scenario). You’ll also need to take care not to introduce an unwanted dependency into the unit-test environment too (but it can be done).

    Neither Spring AOP nor AspectJ does source code weaving btw., and the configuration is hardly complex. In the simplest case you need:

    @Configurable
    public class Model {
    }
    

    and then run with the -javaagent:aspectjweaver.jar option (and spring-aspects.jar on your classpath). And that’s all.

  8. #8 Patrick Lightbody
    on Jan 31st, 2006 at 7:48 am

    Adrian,
    Thanks for the note – that is a bit easier than I expected. I was under the impression from the original article (linked to in this post) that a pre-compilation step was needed. Apologize about that.

    How would something like that work when the class signatures change? WebWork’s QuickStart utility supports automatic class reloading and compilation. Currently Spring in general doesn’t handle this well, since it caches Class instances. But Jeurgen has indicated that this is being fixed for 2.0 M2. If the aspectjweaver doesn’t get in the way with that, even better!

  9. #9 Adrian Colyer
    on Jan 31st, 2006 at 8:10 am

    The -javaagent option is a VM-level option supported in Java 5 (there are other techniques for pre-Java 5, but this is the nicest). If a VM reloads a class, it will be rewoven.

    The option I’ve shown you does what we call “load-time weaving” – ie weaves classes as they are loaded. This is great for development. For production, you probably don’t want to turn on the -javaagent flag as it is VM wide. This is where, in your ant build, you could add an extra “binary weaving” step that links the spring aspects in spring-aspects.jar with your application jar files to produce the final result. This is also probably what you want, as if you don’t need a dynamic environment in production, why pay the overhead of weaving at load-time?

    I have a mostly-written article describing all of this, which I really need to finish off and get published so that folks can see what’s possible…!

  10. #10 Adrian Colyer
    on Jan 31st, 2006 at 8:24 am

    One last thought while I’m here…

    I didn’t want to leave folks with the impression that you are forced to use a Spring annotation. If you are comfortable writing your own aspect, in either code-style or @AspectJ style, there is no need for an annotation at all. If your domain objects are in a package hierarchy with prefix com.myco.myapp.domain then this would look as follows:

    (Code style example)

    public aspect DomainDI extends AbstractBeanConfigurerAspect {
    
    protected pointcut beanCreation(beanIntstance) :
    initialization(com.myco.myapp.domain..*.new(..)) && this(beanInstance);
    
    }
    

    @AspectJ style:

    @Aspect
    public class DomainDI extends AbstractBeanConfigurerAspect {
    
    @Pointcut("initialization(com.myco.myapp.domain..*.new(..)) && this(beanInstance)")
    )
    protected void beanCreation(beanInstance){}
    
    }
    

    (Hope those 2 come out ok, it’s hard to format in this small comment box!)

    If you write an aspect like this, it will work with any existing object in the domain package or sub-packages, with no code changes or other special requirements at all. That’s the power of the pointcut language… annotations are just one convenient way of matching, but not the only way.

  11. #11 Patrick Lightbody
    on Jan 31st, 2006 at 8:29 am

    Thanks for the notes Adrian. I’m definitely eager to give Spring 2.0 a try. I do really wish that there was an alternative to XML configuration though, since I think we should embrace the power of Java and the refactorability that it provides. All I want is that and reloadable components and I’d be very very very happy :)

  12. #12 Patrick Lightbody
    on Jan 31st, 2006 at 12:43 pm

    Oh, and one last thing: I sitll think a standard way to create objects is good direction. For something so simple, we’ve had very complex (and vendor-specific) solutions that could easily be addressed if we all just cooperated a bit. Also, this would mean support for Java 1.3 and 1.4 would be available.

  13. #13 ssozonoff
    on Nov 1st, 2006 at 9:22 am

    I know I am a little late to the party but here goes.

    Adrian presented an alternative to wiring up domain objects without using the @Configurable annotation. This has also been discussed in various blogs and forums, but I have yet to find a complete explanation of how and why.

    Has anyone actually tried doing it? I have been at it for a day now and all I can say is that it is no where near as straightforward as Adrian lays it out. Just to get the basics working and the weaving happening takes some work.

    Now I am fighting with bean name resolving hoping that I can both use bean id’s when instantiating from a Spring and FQN names when new is called outside of Spring…. Anyway @Configurable is currently the only turn key solution to get up and running quick I think (please correct me if I am wrong). Sadly your domain objects will now depend on Spring if you use @Configurable….

Leave a Comment