Improving autofactories/assisted inject

In my two previous posts I wrote about some problems with DI and a solution to part of those problems: assisted inject (as known in Guice)/autofactories (my implementation for CDI). Some problems remained however; for example in the bean constructor, the dependencies (or the environment) are mixed with the data obtained from the factory. That is also why the @FactoryParameter annotation is required.

This shortcoming can be quite easily overcome, by using field injection for dependencies, and constructors for data from the factory. How does it work? And what about testing? Read on :).

The problem

The main goal is to be able to define beans, in which dependency injection works as usual and which can be constructed on-demand with user-supplied data. Something more object-oriented than creating stateless beans where the user-supplied data is passed in method parameters, and something with less boilerplate than implementing factories.

Just to remind, as an example throughout the posts I am using a ProductShipper bean, which needs some outside dependencies (“services”, for example a PriceCalculatorService), and must be provided with a Product object.

The solution

The base interface remains the same:

1
2
3
4
5
6
7
public interface ProductShipper {
     void ship(User target);
 
     interface Factory {
          ProductShipper create(Product product);
     }
}

Again just to remind, the biggest advantage of the nested factory interface is that it is clear what is needed to create a bean (here the shipper), and we spare some typing as we don’t need to write a long class name for the factory.

Now for the implementation. Before both outside dependencies and factory parameters were passed in the constructor. Now, we’ll use field injection, making a clear separation:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@CreatedWith(ProductShipper.Factory.class)
public class ProductShipperImpl implements ProductShipper {
     @Inject
     private PriceCalculatorService priceCalculator;
 
     @Inject
     private TransportService transport;
 
     private final Product product;
 
     public ProductShipperImpl(Product product) {
          this.product = product;
     }
 
     // implement shipTo(User)
}

Looks quite simple. The only thing we needed to do is to specify the factory for the bean (@CreatedWith) and provide a constructor matching the parameters of the factory. Hence, one problem remains: there’s no compile-time checking (only deployment-time), if the arguments lists match. So there’s still room for improvement! :)

Usage

To use the autofactory, you simply have to inject the factory bean. The important thing is that you don’t have to implement the factory bean by hand, it is auto-generated. For example:

1
2
3
4
5
6
7
8
9
10
11
public class Test {
     @Inject
     private ProductShipper.Factory productShipperFactory;
 
     public void test() {
          ProductShipper shipper = productShipperFactory
               .create(new Product("butter"));
 
          shipper.shipTo(new User("me"));
     }
}

Testing

Many would argue that using field injection instead of constructor injection makes the bean much harder to test. But we can improve that quite easily, thanks to the CDIInjector helper class, from softwaremill-util. Here’s how we can test our bean:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import static pl.softwaremill.common.util.CDIInjector.*;
 
public class ProductShipperTest {
     @Test
     public void testShipping() {
          Product product = ...;
          ProductShipper shipper = new ProductShipperImpl(product)
 
          // Here's the important part: "dependency injection"
          into(shipper).inject(mockPriceCalculator, mockService);
 
          // Test goes on ...
     }
}

So instead of setting the fields explicitly via reflection (where we would have to write the field names), we just need to provide the target of injection (into(shipper)), and the objects that we want to be injected (.inject(...)). We can also inject objects with qualifiers.

As always the code is available on github, as part of the softwaremill-common project (softwaremill-cdi release 9 and softwaremill-util release 13). The autofactories implementation is a portable extension (supports both styles: constructor and field/setter injection for dependencies), so all you need to do is to include the jar in your deployment.

Adam

  • I’m not really sure I understood the problem, but it’s been quite a pleasant reading experience and…felt in love with the nested factory interface. Thanks for the readability tip!

    Jacek
    Notatnik Projektanta Java EE

  • The problem is that I want to create (at least partially) managed beans which encapsulate other objects provided at run-time (see http://www.warski.org/blog/?p=272).
    Then I can pass around such a bean, and all the data sits inside, instead of passing the data as method parameters or instead of implementing factories by hand.

    But maybe we’ll get a chance to talk about it f2f one day ;)

    Adam

  • Hi,

    Thanks for this solution for those who want to do OO with Java :)

    I’ll have question about jpa entity.
    If in a JPA entity (created by Hibernate for example) I need to access a service (PriceCalculatorService for example), how can I do?

    It seems to me that it’s not possible.
    That’s why the use of @Configurable seems to be the only way to have services injected into any of my entities (which are often created by mapping frameworks).

    And I agree with you that “the need to weave classes and enrich them with AOP indicates that either the framework or the language lacks something :)”

    What do you think?

    Thanks
    Nico G

  • The use-case you are referring to is one of the roots of the problem :).
    I use one of two solutions:

    1. If I need a dependency e.g. in a JSF converter, some framework’s listener, or in a class that isn’t managed by my DI container, I use static lookup – for CDI, using the D class from softwaremill-util. You can also use that in JPA entities.

    Using it is very simple: D.inject(PriceCalculatorService.class) gives you the appropriate instance.

    For testing, D has a helper method which sets dependencies for a closure, e.g.

    D.withDependencies(dep1, dep2, dep3, new Callable() {
    public void execute() {
    // calling the tested bean which uses D.inject
    }
    }

    This is also great if you need to temporarily replace a dependency, e.g. pretend to login as some user.

    For deployment, you have to hook up into your container’s initialization/shutdown events, and register a dependency provider. For CDI this is a BeanManagerDependencyProvider. Writing a dep provider is very easy e.g. for Seam, Spring etc.

    I think static lookup isn’t that bad as many people say, you can write quite nice code using it. Of course using thread locals etc. See for example the approach to DI taken in Lift.

    2. If possible, I try no to put any functionality into entities – thus I have an anemic model. All logic is implemented in objects that wrap the model objects (new PriceCalculatorService(product).calculate()). This allows me to nicely separate different logical functionalities. But this also requires something like autofactories or – even better – object services – which allow you to create the wrapper objects in a polymorphic way (different services for different subclasses of products). Combining the two is on my todo list ;).

    But otherwise, you are right, injecting dependencies into Hibernate entities isn’t possible without AOP/bytecode instrumentation …

    However, thinking about this for a couple of minutes, maybe if you wrote a Hibernate post-load event listener, and passed that object to your DI container to configure (in CDI that would be obtaining an injection traget and performing the injection, in Spring probably different), then maybe it could work. Something to investigate certainly :)

    Adam

  • Pingback: Dependency Injection in Scala: Extending the Cake Pattern @ Blog of Adam Warski()

  • Hi Adam,

    How (and where) do declare your transaction when you’re doing OO with java?

    In Spring you have @Transactional, which requires AOP, which implies de facto the use of @Configurable.

    An other solution would be to add an extra layer to handle this. But it seems to be a bit over-engineering if you have a little application.

    What do you think?
    Do you have an other solution?

    (Moreover this question is not just about transactio, but every aspect of an application which is handle by AOP, like security)

    Thanks

    Nicolas G

  • It depends of course ;).
    In Seam or JSF apps for transactions I use a transaction phase listener, that is a TX is started when a request starts and commits when a request ends.
    In CDI/Weld apps that don’t use JSF I use @Transactional with an interceptor (so AOP).
    In Lift (Scala) you also can have a tx-per-request.

    I don’t have anything against AOP in principle; for true cross-cutting concernes like security or TX it is great. Still, if it’s so useful, I think it’s good to explore language features which could make it a “first-class” citizen. And I’m not necessarily thinking of Java, but of programming languages in general.

    Adam

  • Pingback: Assisted Inject « Kombinat Programmproduktion West()