Rich Domain Injection stands for dependency injection into domain objects that are not instantiated by the container.

Such injection is useful to avoid "Anemic Domain Model" that's considered "Anti-pattern" by Martin Fowler, because in order for a domain object to be "rich", it is sometimes necessary to have some dependencies to other services or objects.

Spring 2.0 gives a solution which requires Spring specific annotation and AspectJ pre-compilation.

The Nuts' solution requires none. Except the xml configuration, no Java code is dependent on the container API.

I'll use Craig Wall's example for demonstration. To avoid arguments on "persistence is not part of domain" topic, I changed the example a little bit so that it uses a general Service object.

Customer

A Customer class:

public class Customer {
  private Integer id;
  private String name;
    
  public Customer() {}

  public Integer getId() {
      return id;
  }

  public void setId(Integer id) {
      this.id = id;
  }

  public String getName() {
      return name;
  }

  public void setName(String name) {
      this.name = name;
  }
  // business functions
  public void doBusiness() {
      service.serve(this);
  }

  // injected service
  private SomeService service;
  public void setSomeService(SomeService) {
      this.service = service;
  }
}

Note, there's absolutely no indication of which infrastructure is to be used to inject this dependency, therefore no lock-in to any container product.

Decorator

Note, this is just to demonstrate how things work. The final solution implements the decorator for you if you are not a fan of DIY.

The idea is to decorate the CustomerDao interface (Yes, we require the CustomerDao be an interface because we do not want to rely on cglib.) so that it automatically injects dependency.

The pseudo code of CustomerDao decorator class should look like:

class InjectingCustomerDao implements CustomerDao{
  private final CustomerDao dao;
  public Customer load(...){
    Customer customer = dao.load(...);
    inject dependency into customer;
    return customer;
  }
  ...
}

We have yet to implement the "inject dependency into customer" logic. And it is still object oriented. We abstract the notion with an interface. (As we just said, the final solution does not require you to worry about this interface. It is hidden under the hood.)

public interface Injector{
  void inject(Object obj);
}

The InjectingCustomerDao can be implemented as:

class InjectingCustomerDao implements CustomerDao{
  private final CustomerDao dao;
  private final Injector injector;
  public Customer load(...){
    Customer customer = dao.load(...);
    injector.inject(customer);
    return customer;
  }
  ...
}

Factory instead of "new"

Since this solution does not use AOP, constructor of Customer is not intercepted. Hence use of "new Customer()" will not get the dependencies injected.
To get around that, we recommend using a CustomerFactory interface instead of the straight "new".

public interface CustomerFactory{
  Customer createCustomer();
}

Service

Using CustomerFactory, the CustomerService implementation becomes:

public class CustomerServiceImpl implements CustomerService {
  public CustomerServiceImpl() {}  
  public void loadAndDoBusiness(Integer id) {
    Customer original = dao.load(id);    
    Customer duplicate = factory.createCustomer();
    duplicate.setId(original.getId() + 1);
    duplicate.setName(original.getName());
    
    original.setName("Michael Walls");
    
    original.doBusiness();
    duplicate.doBusiness();
  }
  
  private final CustomerDao dao;
  private final CustomerFactory factory;
  public CustomerServiceImpl(CustomerDao dao, CustomerFactory factory){
    this.dao = dao;
    this.factory = factory;
  }
}

Configure it using Nuts

The problem is now reduced to an implementation of "Injector". Since CustomerDao is configured in xml, CustomerFactory is configured in xml, CustomerServiceImpl is also congifured in xml, we have all the control that we need.

The configuration for the injection logic is expressed using the <binder> tag:

<bean id="someservice" class="SomeService" .../>
<binder id="customer injection" var="customer">
  <bean component="$customer" props="{someService=$someservice}"/>
</binder>

The configuration for a CustomerFactory implementation that injects dependency is:

<factory id="customer factory" type="CustomerFactory">
  <bind binder="$customer injection">
    <ctor class="Customer"/>
  </bind>
</factory>

The configuration for CustomerDao also uses dynamic proxy, therefore no explicit implementation of CustomerDao decorator is necessary:

<inject id="rich_dao" type="CustomerDao"
    injectee="Customer"
    injection="$customer injection">
    <bean id="raw dao" class="CustomerDaoImpl" .../>
</inject>

Put everthing together, the configuration files looks like:

<!-- injection logic -->
<bean id="someservice" class="SomeService" .../>
<binder id="customer injection" var="customer">
  <bean component="$customer" props="{someService=$someservice}"/>
</binder>

<!-- CustomerFactory implementation -->
<factory id="customer factory" type="CustomerFactory">
  <bind binder="$customer injection">
    <ctor class="Customer"/>
  </bind>
</factory>


<!--The dao that injects dependencies -->
<inject id="rich dao" type="CustomerDao"
    injectee="Customer"
    injection="$customer injection">
    <bean id="raw dao" class="CustomerDaoImpl" .../>
</inject>

<!--CustomerService implementation-->
<ctor id="customer service" class="CustomerServiceImpl"
    args="$rich dao, $customer factory"/>

The Java code you ever need to implement is Customer and CustomerServiceImpl, with aboslutely zero dependency on infrastructure.

Summary

With Spring 2.0, we get the convenience to use "new Customer()" directly in the code. Dependency injection is auto-magically handled by AspectJ. The price to pay is that we have to use spring specific annotation in the domain object. Plus, the code can only work within an AOP framework because "new Customer().doBusiness()" is a plain bug without AOP semantics in place to sneak in logic.

With Nuts, No annotation is required. The code is purely object oriented without a need of AOP. If I like, I can always hand-write the CustomerDao decorator to inject dependencies myself. This makes the code portable and easy to unit-test. The price to pay is that we have to use a CustomerFactory to create Customer objects. "new Customer()" doesn't bring the dependencies we want.