WYTIWYR : What You Test Is What You Run

I’m fed up with unit testing !

It’s 2012 and my first resolution of the year is to finally tell the truth about testing : unit testing is pretty much useless when your code runs inside a container. How do you unit test an EJB which relies on the container services (i.e transaction, injection, security…) ? Well, you mock the database access, you mock your security layer, you mock your dependencies, you mock your validation layer… to test what ? A bit of business logic. Yes. Unit test is interesting when you have complex business logic to test so you can have quick feedback. Otherwise, it’s a waste of time which doesn’t test your container services. So I’m not saying unit testing is completely useless, I’m saying that integration testing is also to be considered when you run your code inside a Java EE container.

In this post I’ll show you how to unit test an EJB with Mockito and how to do integration test with and without Arquillian.

Use case

So let’s take a simple use case (but of course, in real life it’s more complex) : I have a Book entity with a complex named query (well, sort of) and an EJB that queries the entity (CRUD operations + calling the named query). Because my JPQL query is complex and I have a bug in production, I want to reproduce the bug and correct the JPQL query. Because I like Java EE 6 and CDI I use extensively some artifacts that need to be injected (such as a Logger, DataSourceDefinition and so on).

As you can see in the class diagram, I have the following classes :

  • ItemEJB : a stateless EJB with a @Path annotation to add REST services. It manipulates the Book entity.
  • Book : entity with JPA annotation for persistence and query as well as JAXB annotations for XML marshaling.
  • IsbnGenerator : CDI bean that generates an ISBN number for the book.
  • DatabasePopulator : startup singleton that persists a few books into the database.
  • ApplicationConfig : helper class annotated with @ApplicationPath to declare all REST services under the /rs URL.
  • DatabaseResource : produces an injectable EntityManager.
  • LogResource : produces an injectable logger.

The Book entity

The Book entity is pretty simple but some things have to be highlighted :

@Entity
@NamedQueries({
@NamedQuery(name = Book.FIND_ALL_SCIFI, query = "SELECT b FROM Book b WHERE 'scifi' member of b.tags ORDER BY b.id DESC")
})
public class Book {

  public static final String FIND_ALL_SCIFI = "Book.findAllScifiBooks";

  @Id @GeneratedValue
  private Long id;
  @NotNull
  private String title;
  private Float price;
  private String description;
  private String isbn;
  @ElementCollection
  private List tags = new ArrayList();
  ..

This entity has a named query which retreives all the scifi books from the database and I need to test it (this query is pretty simple but imagine an harder one). The JPA provider will generate an id automatically thanks to @GeneratedValue. The integration between JPA with Bean Validation will make sure I cannot insert a Book with a null title (thanks to @NotNull). These services have to be mocked in unit testing (not in integration test as you will see).

The ItemEJB

The ItemEJB is a Stateless EJB with REST capabilites doing CRUD operations and invoking the entity named query :

@Stateless
public class ItemEJB {

  @Inject
  private EntityManager em;

  @Inject
  private IsbnGenerator numberGenerator;

  @Inject
  private Logger logger;

  public Book createBook(Book book) {
    book.setIsbn(numberGenerator.generateNumber());
    em.persist(book);
    return book;
  }

  public void removeBook(Book book) {
    em.remove(em.merge(book));
  }

  public List findAllScifiBooks() {
    logger.info("###### findAllScifiBooks ");
    return em.createNamedQuery(Book.FIND_ALL_SCIFI, Book.class).getResultList();
  }
  ...
}

This POJO uses several services from the container. First of all, every method is transactional (without any extra boiler plate code, just because it’s annotated with @Stateless). Then, this EJB gets injected an EntityManager that has been produced (see below), a helper class (the IsbnGenerator POJO) and a logger (I’ll use the good old java.util.logging so my code doesn’t have external dependencies). Again, these services will have to be mocked in unit testing.

DataSource

I need a datasource to access a database. Because I want to do some testing, Derby in-memory database will do. And because I’m pretty lazy and don’t want to create a datasource inside my container using the admin console, I use the @DataSourceDefinition annotation to make my life easier :

@DataSourceDefinition(name = "java:app/jdbc/sampleArquilianWytiwyrDS",
className = "org.apache.derby.jdbc.EmbeddedDriver",
url = "jdbc:derby:memory:sampleArquilianWytiwyrDB;create=true;user=app;password=app"
)
public class DatabaseResource {

  @Produces
  @PersistenceContext(unitName = "sampleArquilianWytiwyrPU")
  private EntityManager em;
}

As you can see I produce my EntityManager so it can be injected with @Inject. In unit testing this class is pretty much useless as no datasource can be used and injection as to be mocked.

Testing scenario

As I said, I want to test a complex scenario with all the container services available (so this is not unit testing per se). Here is the scenario :

  • I get all the scifi books from the database (using the named query that looks for the scifi tag)
  • I persist three books : one that fills the query, another one that doesn’t and a third one that has a null title which will not get persisted (due to Bean Validation ConstraintViolationException)
  • I get all the scifi books from the database again and make sure there is an extra one
  • I remove all the entities from the database
  • I get all the scifi books from the database again and make sure we have the initial number of books

Implementing the scenario with unit testing

I’m going to say this again to make sure I don’t receive thousands of emails from unit testing fanatics : the scenario described above is not a unit test, but I want to show how you can unit test your EJB with Mockito (and how painful and useless it is). So let’s go, I’ll start with the code and explain it later :
@RunWith(MockitoJUnitRunner.class)
public class ItemEJBTest {

  @Mock
  private EntityManager mockedEntityManager;
  @Mock
  private TypedQuery mockedQuery;
  private ItemEJB itemEJB;

  @Before
  public void initDependencies() throws Exception {
    itemEJB = new ItemEJB();
    itemEJB.setEntityManager(mockedEntityManager);
    itemEJB.setNumberGenerator(new IsbnGenerator());
    itemEJB.setLogger(Logger.getLogger(ItemEJB.class.getName()));
  }

  @Test
  public void shouldFindAllScifiBooks() throws Exception {

    List books = new ArrayList();

    // Finds all the scifi books
    when(mockedEntityManager.createNamedQuery(Book.FIND_ALL_SCIFI, Book.class)).thenReturn(mockedQuery);
    when(mockedQuery.getResultList()).thenReturn(books);
    int initialNumberOfScifiBooks = itemEJB.findAllScifiBooks().size();

    // Creates the books
    Book scifiBook = new Book("Scifi book", 12.5f, "Should fill the query", 345, false, "English", "scifi");
    Book itBook = new Book("Non scifi book", 42.5f, "Should not fill the query", 457, false, "English", "it");
    Book nullBook = new Book(null, 12.5f, "Null title should fail", 457, true, "English", "scifi");

    // Persists the books
    itemEJB.createBook(scifiBook);
    itemEJB.createBook(itBook);
    verify(mockedEntityManager, times(2)).persist(any());

    try {
      doThrow(ConstraintViolationException.class).when(mockedEntityManager).persist(nullBook);
      itemEJB.createBook(nullBook);
      fail("should not persist a book with a null title");
    } catch (ConstraintViolationException e) {
    }

    // Finds all the scifi books again and make sure there is an extra one
    books.add(scifiBook);
    when(mockedQuery.getResultList()).thenReturn(books);
    assertEquals("Should have one extra scifi book", initialNumberOfScifiBooks + 1, itemEJB.findAllScifiBoks().size());

    // Deletes the books
    itemEJB.removeBook(scifiBook);
    itemEJB.removeBook(itBook);
    verify(mockedEntityManager, times(2)).remove(any());

    // Finds all the scifi books again and make sure we have the same initial numbers
    books = new ArrayList();
    when(mockedQuery.getResultList()).thenReturn(books);
    assertEquals("Should have initial number of scifi books", initialNumberOfScifiBooks, itemEJB.findAllScifiBooks().size());
  }
}

Some explanation :

  • line number 4 and 6 : thanks to @RunWith(MockitoJUnitRunner.class), I’m mocking the database access by mocking my EntityManager and TypedQuery with the @Mock annotation
  •  line number 12 :  in the initDependencies method that’s where we lose all the container services : we do a new of the ItemEJB (itemEJB = new ItemEJB()) instead of injecting or lookingup the EJB. Instanciating ItemEJB is not seen by the container, so it’s just a POJO without any container services. And because we run in isolation, we have to manually mock or instanciate the dependencies using setters (setEntityManagersetNumberGenerator and setLogger).
  • line number 19 : shouldFindAllScifiBooks implements our testing scenario. As you can see, I use an ArrayList to add my books and Mockito returns this list (instead of the query result). I then persist my books (verify(mockedEntityManager, times(2)).persist(any())) and I want to make sure I get a ConstraintViolationException when persisting a book with a null title (that why I have doThrow(ConstraintViolationException.class).when(mockedEntityManager).persist(nullBook)). To test that my query returns an extra book I just add the object to the list (books.add(scifiBook)) and remove it afterwards (books.remove(scifiBook)).

As you can see, I haven’t tested my JPQL query, the code is not that nice, and I have to do many Mockito tricks to simulate what I want. Isn’t that a test smell ? A Mockery ? We shouldn’t mock third-party libraries. So let’s do integration tests.

Implementing the scenario with integration testing

I can hear you saying “Integration test in Java EE is difficult, don’t do that“. This was true in the past but not anymore. Integration testing use to be nearly impossible, that’s why we had no choice but unit test and mock all the services. But today, thanks to Java EE 6, we can easily do integration testing. How ? By using standard (and some time non standard) APIs or testing frameworks such as Arquillian :

  • EJBContainer.createEJBContainer() : creates an in-memory EJB container where you can deploy and use your EJB
  • Persistence.createEntityManagerFactory() : creates a JPA provider so you can manipulate entities
  • Validation.buildDefaultValidatorFactory() : gets a validator to validate your beans
  • ActiveMQConnectionFactory : creates an in-memory JMS broker (non-standard)
  • ServletTester : Jetty helper class to test your servlets and web services in-memory (non-standard, I whish we had a standard WebContainer API like in EJBs)

Without Arquillian (i.e EJBContainer)

Let’s start with the simplest standard integration test for an EJB : using the javax.ejb.embeddable.EJBContainer API. This API was created in EJB 3.1 and is used to execute an EJB application in an embeddable container (in a standard way). Here is the code of our scenarion with the EJBContainer (BTW I’m using GlassFish 3.1 as the implementation) :

public class ItemEJBWithoutArquillianIT {

    private static EJBContainer ec;
    private static Context ctx;

    @BeforeClass
    public static void initContainer() throws Exception {
        Map properties = new HashMap();
        properties.put(EJBContainer.MODULES, new File[]{new File("target/classes"), new File("target/test-classes")});
        ec = EJBContainer.createEJBContainer(properties);
        ctx = ec.getContext();
    }

    @AfterClass
    public static void closeContainer() throws Exception {
        if (ec != null) {
            ec.close();
        }
    }

    @Test
    public void shouldFindAllScifiBooks() throws Exception {

        // Check JNDI dependencies
        assertNotNull(ctx.lookup("java:global/classes/ItemEJB"));
        assertNotNull(ctx.lookup("java:global/jdbc/sampleArquilianWytiwyrDS"));

        // Looks up for the EJB
        ItemEJB itemEJB = (ItemEJB) ctx.lookup("java:global/classes/ItemEJB");

        // Finds all the scifi books
        int initialNumberOfScifiBooks = itemEJB.findAllScifiBooks().size();

        // Creates the books
        Book scifiBook = new Book("Scifi book", 12.5f, "Should fill the query", 345, false, "English", "scifi");
        Book itBook = new Book("Non scifi book", 42.5f, "Should not fill the query", 457, false, "English", "it");
        Book nullBook = new Book(null, 12.5f, "Null title should fail", 457, true, "English", "scifi");

        // Persists the books
        itemEJB.createBook(scifiBook);
        itemEJB.createBook(itBook);
        try {
            itemEJB.createBook(nullBook);
            fail("should not persist a book with a null title");
        } catch (Exception e) {
            assertTrue(e.getCause() instanceof ConstraintViolationException);
        }

        // Finds all the scifi books again and make sure there is an extra one
        assertEquals("Should have one extra scifi book", initialNumberOfScifiBooks + 1, itemEJB.findAllScifiBooks().size());

        // Deletes the books
        itemEJB.removeBook(scifiBook);
        itemEJB.removeBook(itBook);

        // Finds all the scifi books again and make sure we have the same initial numbers
        assertEquals("Should have initial number of scifi books", initialNumberOfScifiBooks, itemEJB.findAllScifiBooks().size());
    }
}

Some explanation :

  • line number 7 : here I create my embedded EJB container and get the JNDI context. As you can see, I don’t have to mock anything (EntityManager, injection and so on) because from now on my code will be running in an embedded container (which is the same container that you will be running in production, but in runtime mode instead of in-memory)
  • line number 15 : closes the EJB container once the test is passed
  • line number 22 : in this method I implement our testing scenario, with no mocks. I lookup my EJB using JNDI and invoke the needed methods (findAllScifiBooks, createBook and removeBook) which will be intercepted by the container that will give me all the services (transactions, injection, lifecycle…)
  • line number 26 : because I’m running inside a container, I can even lookup my datasource (because it has been deployed thanks to @DataSourceDefinition
  • line number 43 : if I persist a book with a null title, Bean Validation will throw a constraint violation (a real one, I don’t have to mock it)

With Arquillian

Arquillian is a JBoss project that can execute test cases inside a container (embedded, local or remote). And when I say a container, it can run the same test in several ones (GlassFish, JBoss…). In my case I’m using GlassFish, so as you can see, Arquillian is not stuck to JBoss. I will write about multiple server deployment later, but for now, let’s see how an integration test with Arquillian differs from one with the EJBContainer API :

@RunWith(Arquillian.class)
public class ItemEJBWithArquillianIT {

    @Inject
    private ItemEJB itemEJB;

    @Deployment
    public static JavaArchive createTestArchive() {
        JavaArchive archive = ShrinkWrap.create(JavaArchive.class)
                .addPackage(Book.class.getPackage())
                .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml")
                .addAsResource("META-INF/persistence.xml", "META-INF/persistence.xml");
        return archive;
    }

    @Test
    public void shouldFindAllScifiBooks() throws Exception {

        // Check JNDI dependencies
        Context ctx = new InitialContext();
        assertNotNull(ctx.lookup("java:global/jdbc/sampleArquilianWytiwyrDS"));

        // Finds all the scifi books
        int initialNumberOfScifiBooks = itemEJB.findAllScifiBooks().size();

        // Creates the books
        Book scifiBook = new Book("Scifi book", 12.5f, "Should fill the query", 345, false, "English", "scifi");
        Book itBook = new Book("Non scifi book", 42.5f, "Should not fill the query", 457, false, "English", "it");
        Book nullBook = new Book(null, 12.5f, "Null title should fail", 457, true, "English", "scifi");

        // Persists the books
        itemEJB.createBook(scifiBook);
        itemEJB.createBook(itBook);
        try {
            itemEJB.createBook(nullBook);
            fail("should not persist a book with a null title");
        } catch (Exception e) {
            assertTrue(e.getCause() instanceof ConstraintViolationException);
        }

        // Finds all the scifi books again and make sure there is an extra one
        assertEquals("Should have one extra scifi book", initialNumberOfScifiBooks + 1, itemEJB.findAllScifiBooks().size());

        // Deletes the books
        itemEJB.removeBook(scifiBook);
        itemEJB.removeBook(itBook);

        // Finds all the scifi books again and make sure we have the same initial numbers
        assertEquals("Should have initial number of scifi books", initialNumberOfScifiBooks, itemEJB.findAllScifiBooks().size());
    }
}

Some explanation :

  • line number 4 : thanks to Arquillian, I can inject a reference of my EJB instead of looking it up. My test runs inside the container, so I can use the injection service of this container
  • line number 8 : the createTestArchive method uses ShrinkWrap to create an archive which will then be deployed by Arquillian in the container
  • line number 17 : the code of the integration test is nearly the same as the one we say before
In this example it’s difficult to see the benefit of Arquillian as both test classes (with EJBContainer and with Arquillian) are similar. Arquillian is not standard, the EJBContainer API is. But I’ll spend more blogs explaining you the benefit in the long run.

Some metrics

Ok, some metrics now. How much does it cost to run a unit test vs integration tests ? I measured each of these tests (on my fantastic Mac Book Pro – i7 – 8Gb RAM – SSD drive) and here is the execution time :

  • unit testing : 195 milliseconds to run
  • integration test without Arquillian : 5.3 seconds (that’s 27 times slower than unit testing)
  • integration test with Arquillian : 6.1 seconds (that’s 31 times slower than unit testing)
As you can see, unit testing is by far much faster to execute. Unit testing gives you a quick feedback and you can really develop and test continuously. It’s still time consuming to do with integration test.

Conclusion

There is unit testing and integration testing. Historically integration testing was pretty much impossible in Java EE and you had to do many different tricks. That’s why we used extensively unit testing and mocked even objects that we don’t owe (like the EntityManager). But since Java EE 6, thanks to all our container factories (EJBContainerEntityManagerFactoryValidatorFactory…) we can now easily use these container and their services in an embedded mode. Unit testing is good to test business code or code in isolation (mocking external components) but we have to remember that we have easy integration testing now and we should use it to test code interacting with external components or services.

But the world is not perfect… yet. The big advantage of unit testing is the quick feedback because unit tests run faster. But, because you are mocking so many services, you don’t have a clue how your code will behave in production. Integration test uses the container and the container services, so you know that What You Test Is What You Run.

I little bit of hope now. A few month ago I wrote a (long) post about startup time of most of the Java EE 6 application servers. Most of the application servers startup in less than 4 seconds. If you look at the application servers history, that is a huge improvment in the last years. Same thing will happen with embedded containers and integration test framework such as Arquillian : they will get faster and faster, and soon, running your in-memory database and in-memory container will cost you little resources. Having fast integration tests that’s what we want !

Thanks

I would like to thank Brice Duteil, a Mockito committer who gave me some advices on Mockito.

References


Injection with CDI (Part III)

If you follow this blog you should know that latelly I’ve been writing (and talking) about CDI (Contexts and Dependency Injection). CDI has many aspects to it but until now I’ve focused on how to boostrap CDI in several environments, how to add CDI to an existing Java EE 6 application,  and more recently how to use injection with CDI. Actually this post is the third on CDI Injection : Part I focused on default injection and qualifiers, and Part II on all the possible injection points (field, constructor and setters). In this post I’ll explain producers or “how you can inject anything anywhere in a type safe manner“.

Injecting just beans ?

Until now I’ve shown you how to inject beans with a simple @Inject. If we focus on the book number generator example I’ve been using, we have a Servlet and a RESTService being injected an implementation of the NumberGenerator interface. Thanks to qualifiers, the servlet can specifically ask to get the IsbnGenerator by specifying the @ThirteenDigit qualifier on the injection point and the rest service an IssnGenerator with a @EightDigits (check my first post). The following class diagram shows you some combinations of bean injection :

But as you can see, all this is are beans injecting other beans. Can we just inject beans with CDI ? The answer is no, you can inject anything anywhere.

Producers

Yes, you can inject anything anywhere, the only thing you have to do is produce the thing you want to inject. For that, CDI has producers (a nice implementation of the Factory pattern) A producer exposes any sort of :

  • Class : unrestricted set of bean types, superclass, and all interfaces it implements directly or indirectly
  • Interface : unrestricted set of bean types, interfaces it extends directly or indirectly, and java.lang.Object
  • Primitive and Java array type

So by that you can inject a java.util.Date, java.lang.String or even an int. Let’s start by producing and injecting some data types and primitives.

Producing data types and primitives

One example of injecting anything anywhere is the possibility to inject data types or primitives. So let’s inject a String and an int. For that I need to add extra classes to our model. Until now, the IsbnGenerator would generate a random number like 13-124-454644-4. I can say that this number is made of a String that acts like a prefix (13-124) and an int that acts like a suffix (4). The following class diagram shows the two new classes PrefixGenerator and PostfixGeneratorthat will be used by the number generators :

If we look at the code of the PrefixGenerator for example, you can see that the class itself is not annotated by any qualifier, but the methods are. The method getIsbnPrefix returns a String that is qualified with @ThirteenDigits. This String is produced by CDI (thanks to @Produces), meaning that you can now inject it with @Inject using its qualifier (@ThirteenDigits)

public class PrefixGenerator {

    @Produces @ThirteenDigits
    public String getIsbnPrefix() {
        return "13-84356";
    }

    @Produces @EightDigits
    public String getIssnPrefix() {
        return "8";
    }
}

And now look carefully at the class  PostfixGenerator. The code is exactly the same as previously except in this case we produce an intthat can now be injected.

public class PostfixGenerator {

    @Produces @ThirteenDigits
    public int getIsbnPostfix() {
        return 13;
    }

    @Produces @EightDigits
    public int getIssnPostfix() {
        return 8;
    }
}

So now let’s change the way an ISBN number is generated. The bean IsbnGenerator now injects both a String and an int with @Inject @ThirteenDigits. You understand now what strong typing means with CDI.  Using the same syntax (@Inject @ThirteenDigits), CDI knows that it needs to inject a String, an int or an implementation of a NumberGenerator.

@ThirteenDigits
public class IsbnGenerator implements NumberGenerator {

    @Inject @ThirteenDigits
    private String prefix;

    @Inject @ThirteenDigits
    private int postfix;

	public String generateNumber() {
        return prefix + "-" + Math.abs(new Random().nextInt()) + "-" + postfix;
    }
}

Injecting Java EE resources with producer fields

So if CDI can inject anything anywhere, if CDI can even inject Strings and integers, what about Java EE resources ? That’s another story and producers are here to help. As I’ve said before, CDI is all about type safety : CDI doesn’t like Strings, so there is no way to inject a resource by its JNDI name such as @Inject(name="jms/OrderQueue"). A common example is the entity manager. This is how you must inject it in Java EE 6 if you don’t use CDI :

@Stateless
public class ItemEJB {

    @PersistenceContext(unitName = "cdiPU")
    private EntityManager em;
    ...
}

So why can’t you just @Inject an entity manager? If you remember my first post about ambiguous injection, this is the same problem. You can have several persistence units (named with a string), so if you just use an @Inject, CDI will not know which persistence unit to inject. Instead you must produce the entity manager first, give it a name (if you don’t want the @Default) and then an @Inject as follow :

public class DatabaseProducer {

    @Produces
    @PersistenceContext(unitName = "cdiPU")
    @BookStoreDatabase
    private EntityManager em;
}

The DatabaseProducer class uses the @PersistenceContext to inject the entity manager with the persistence unit cdiPU. It gives it a name using a qualifier (@BookStoreDatabase) and produces it so it can now be injected in an EJB as follow :

@Stateless
public class ItemEJB {

    @Inject
    @BookStoreDatabase
    private EntityManager em;
    ...
}

Another nice use case is to produce JMS factories and destinations. @Resource allows you to get a JNDI reference to a specific JMS factory or destination, the qualifier @Order gives it a name, and the @Produces allows you to inject it :

public class JMSResourceProducer {

    @Produces @Order @Resource(name = "jms/OrderConnectionFactory")
    private QueueConnectionFactory orderConnectionFactory;

    @Produces @Order @Resource(name = "jms/OrderQueue")
    private Queue orderQueue;
}

Now your EJB can use @Inject in a type-safe way :

@Stateless
public class ItemEJB {

    @Inject @Order
    private QueueConnectionFactory orderConnectionFactory;

    @Inject @Order
    private Queue orderQueue;
    ...
}

Producing Java EE resources with producer methods

The examples above are pretty simple : produce a field and you can then inject it. That’s called producer field. But sometimes you need a more complex business logic to produce a bean, that’s what we called producer method. Let’s take another use case. When you need to send a JMS message you always end up injecting a JMS Factory, a destination (queue or topic) creating a connection, then a session and so on until you actually send your message. Because this code is repetitive and error prone, why not externalize all of if into a single class and produce a session so the other components can use when sending a message. This class could look something like that :

public class JMSResourceProducer {

    @Resource(name = "jms/OrderConnectionFactory")
    private QueueConnectionFactory orderConnectionFactory;
    @Produces @Order @Resource(name = "jms/OrderQueue")
    private Queue orderQueue;

    @Produces @Order
    public QueueConnection createOrderConnection() throws JMSException {
        return orderConnectionFactory.createQueueConnection();
    }

    @Produces @Order
    public QueueSession createOrderSession(@Order QueueConnection conn) throws JMSException {
        return conn.createQueueSession(true, Session.AUTO_ACKNOWLEDGE);
    }
}

First, the class uses the @Resource to get a reference of the QueueConnectionFactory and Queue. For the same reason I just explain above, you can have several JMS factories and destinations and you must distinguish them by their JNDI name. And because CDI does not allow you to give a string name on an injection point, you must still use @Resource instead of @Inject. The createOrderConnection method take a QueueConnectionFactory creates a QueueConnection and produces it (while giving it the name of @Order). If you look carefully at the method createOrderSession it takes the produced QueueConnection and creates a QueueSession. An external component then just needs to inject the JMS session without going through the process of creating it :

@Stateless
public class ItemEJB {

    @Inject @Order
    private QueueSession session;

    @Inject @Order
    private Queue orderQueue;

    private void sendOrder(Book book) throws Exception {
        QueueSender sender = session.createSender(orderQueue);
        TextMessage message = session.createTextMessage();
        message.setText(marshall(book));
        sender.send(message);
    }
    ...
}

Producing and… disposing

I can hear you saying “ok, that’s nice, I have an external class doing all the plumbing and creating a connection and a session…. but who is going to close it ?“. Indeed, someone needs to free these resources by closing them. And that’s when CDI brings you another nice bit of magic : @Disposes.

public class JMSResourceProducer {

    @Resource(name = "jms/OrderConnectionFactory")
    private QueueConnectionFactory orderConnectionFactory;
    @Produces @Order @Resource(name = "jms/OrderQueue")
    private Queue orderQueue;

    @Produces @Order
    public QueueConnection createOrderConnection() throws JMSException {
        return orderConnectionFactory.createQueueConnection();
    }

    @Produces @Order
    public QueueSession createOrderSession(@Order QueueConnection conn) throws JMSException {
        return conn.createQueueSession(true, Session.AUTO_ACKNOWLEDGE);
    }

    public void closeOrderSession(@Disposes @Order QueueConnection conn) throws JMSException {
        conn.close();
    }

    public void closeOrderSession(@Disposes @Order QueueSession session) throws JMSException {
        session.close();
    }
}

To ask CDI to close a resource you just need to create a method which signature is the same as the one that created it (createOrderSession(@Order QueueConnection conn) creates a session and closeOrderSession(@Order QueueConnection conn) closes it) and add a @Disposes. CDI will dispose the resources in the right order (session first, connection second) for you. I haven’t mentioned it yet but CDI will create and dispose resources depending on the scope (resquest, session, application, conversation…). But that’s for another post.

Conclusion

As you’ve seen in my previous posts (Part I, Part II), CDI is about injection (I’ll explain other topics later). So far I’ve been showing you how to inject beans, but you know now that you can inject anything (String, integer, entity manager, JMS factories…) anywhere (in POJOs, Servlets, EJBs…). You just need to produce what you need to inject (either with field producers or method producers).
The next article will cover alternatives, so stay tuned.

Download

Download the code, give it a try, and give me some feedback.

References


To inject or not to inject: CDI is the question

Two weeks ago I did a little tour around several JUGs and conferences to talk about dependency injections with CDI. The final goal of this road movie was to end up at GeeCon in Krakow. It was my second time at GeeCon and I have to say that this conference is like good wine : getting better with age. This community based conference is on its third edition and attracts people through out central and eastern Europe. Plenty of good speakers, nice location, skilled attendees… and a lot of fun (GeeCon organizers are party addicts). So make sure you mark this conference into your agenda for next year.

In the meantime, I have made my slides available. Enjoy and do not hesitate to send me some feedback.


Injection with CDI (Part II)

This is the second post based on pure CDI Injection (see Part I) after having talked about how to bootstrap CDI in several environments and how to add CDI to an existing Java EE 6 application. In this post I quickly want to show the different injection points in CDI : field, constructor and setter. To illustrate these different injection points I’ll use a subset of the previous example : a servlet injecting an ISBN generator POJO :

Field injection

Until now, in all the previous posts, you’ve seen the @Inject annotation put on fields (attributes).

@WebServlet(urlPatterns = "/itemServlet")
public class ItemServlet extends HttpServlet {

    @Inject
    @ThirteenDigits
    private NumberGenerator numberGenerator;

    @Inject
    private ItemEJB itemEJB;
    ...
}

As you can see in the code above, the @Inject and the qualifiers (here @ThirteenDigits) annotate an attribute. But like many other injection frameworks, in CDI you can also have constructor and setter injection.

Constructor injection

Instead of annotating the attributes, you can add the @Inject annotation on a constructor. If you then need to use qualifiers, you can add them to the attributes of the constructor as follow :

@WebServlet(urlPatterns = "/itemServlet")
public class ItemServlet extends HttpServlet {

    private NumberGenerator numberGenerator;
    private ItemEJB itemEJB;

    @Inject
    public ItemServlet(@ThirteenDigits NumberGenerator numberGenerator, ItemEJB itemEJB) {
        this.numberGenerator = numberGenerator;
        this.itemEJB = itemEJB;
    }
    ...
}

As you can see, the @Inject is not on the field but on the constructor. On the other hand, @ThirteenDigits doesn’t qualify the constructor but the numberGenerator parameter itself (which is logical). You can also mix field and constructor injection if you want (below I use constructor injection and attribute injection on the EJB) :

@WebServlet(urlPatterns = "/itemServlet")
public class ItemServlet extends HttpServlet {

    private NumberGenerator numberGenerator;

    @Inject
    private ItemEJB itemEJB;

    @Inject
    public ItemServlet(@ThirteenDigits NumberGenerator numberGenerator) {
        this.numberGenerator = numberGenerator;
    }
    ...
}

But the rule is : you can only have one constructor injection point. The container is the one doing injection, not you (you can’t invoke a constructor in a managed environment, well, you can, but it will not work as you expect). There is only one bean constructor allowed so the container can do its job of injecting the right references. The following is invalid :

@WebServlet(urlPatterns = "/itemServlet")
public class ItemServlet extends HttpServlet {

    private NumberGenerator numberGenerator;
    private ItemEJB itemEJB;

    @Inject
    public ItemServlet(@ThirteenDigits NumberGenerator numberGenerator, ItemEJB itemEJB) {
        this.numberGenerator = numberGenerator;
        this.itemEJB = itemEJB;
    }

    @Inject
    public ItemServlet(@ThirteenDigits NumberGenerator numberGenerator) {
        this.numberGenerator = numberGenerator;
    }
	...
}

If you have more than one bean constuctor, this is what you get (the error code and message is Weld specific of course) :

WELD-000812 Cannot determine constructor to use for public@WebServlet class ItemServlet. Possible constructors [[constructor] @Inject public ItemServlet(NumberGenerator, ItemEJB), [constructor] @Inject public ItemServlet(NumberGenerator)]

On the other hand, it is syntactically legal to have field and constructor injection at the same time (but useless) :

@WebServlet(urlPatterns = "/itemServlet")
public class ItemServlet extends HttpServlet {

    @Inject @ThirteenDigits
    private NumberGenerator numberGenerator;
    @Inject
    private ItemEJB itemEJB;

    @Inject
    public ItemServlet(@ThirteenDigits NumberGenerator numberGenerator, ItemEJB itemEJB) {
        this.numberGenerator = numberGenerator;
        this.itemEJB = itemEJB;
    }
    ...
}

Setter injection

The other choice is to use setter injection which looks like constructor injection. You annotate the setter with @Inject and you qualify the parameters :

@WebServlet(urlPatterns = "/itemServlet")
public class ItemServlet extends HttpServlet {

    private NumberGenerator numberGenerator;
    private ItemEJB itemEJB;

    @Inject
    public void setNumberGenerator(@ThirteenDigits NumberGenerator numberGenerator) {
        this.numberGenerator = numberGenerator;
    }

    @Inject
    public void setItemEJB(ItemEJB itemEJB) {
        this.itemEJB = itemEJB;
    }
    ...
}

When you use constructor or setter injection you need to apply your qualifiers to a parameter. So make sure you have the right @Targets (java.lang.annotation.ElementType.PARAMETER) definition :

@Qualifier
@Retention(RUNTIME)
@Target({FIELD, TYPE, METHOD, PARAMETER})
public @interface ThirteenDigits {
}

Conclusion

One question you could ask (and that’s the one I asked to Pete Muir) is : “when do you use field over constructor or setter injection ?”. There is no real technical answer except that it’s your personal taste. In a managed environment, the container is the one doing all the injection work, it just needs the right injection points. However, with constructor or setter injection you can add some logic if needed (not with field injection). But it looks like setter injection was added for backward compatibility with existing Java Beans.

The next article will cover producers, so stay tuned.

Download

Download the code, give it a try, and give me some feedback.

References


A week in central Europe… with CDI

I haven’t talked much lately at conferences or JUGs. The last one was Devoxx in November 2010 and I have been quite ever since (working on some other plans ;o) But it’s time to do a bit of touring again. This time it will be Central Europe and the topic with injection in CDI. The presentation of the talk is To inject or not to inject: CDI is the question and the description roughly is :

After a quick introduction of CDI (Contexts and Dependency Injection) I will concentrate on dependency injection and the type-safe approach on injection in CDI. If you are fed up of using String based configuration, come to this talk and have a type-safe journey on CDI.

How come I am touring again ? Everything started with an invitation from my friends at GeeCon. I discovered GeeCon in 2009. It was the first edition of this conference in Cracow (Poland) created by the local user group. As I mentioned in my post, I really liked the conference as it felt very professional with good speakers and nice atmosphere. So this year I’ve accepted the invitation and I’m going back to the 2011 edition to talk about injection in CDI…. and on my way, I’ve decided to have some stop-overs :

  • Monday 9th of May – come on listen to my talk at the JUG Cologne in Germany (Map)
  • Tuesday 10th of May – CZJUG (Prague – Czech Republic) : it’s going to be a busy day. I’ll spend the day at the EMEA Oracle User Group (Map) and then go to the JUG to do my talk at 7pm (Map).
  • Wednesday 11th of May – GeeCon (Cracow – Poland) : I’ll be doing a Java EE 6 university talk with my friend Alexis Moussine-Pouchkine. It will be the same talk we did at Devoxx last year, but updated of course
  • Thursday 12th of May - GeeCon (Map) I’ll do my CDI talk
  • On Friday I will have fun and a relaxing time in Cracow (it is such a nice city)
  • Then I’ll visit some friends in Venice (Italy) and stay during the week-end (not talking about Java at all, drinking wine and eating pasta)
  • … and then back home

View Larger Map

I’ll be doing all these trips using my favorite transport : night trains. So if you are anywhere near and want to attend one of my talks… of just have a beer, fill free to come.

See you


Injection with CDI (Part I)

After writing a post about how to bootstrap CDI in your environment and giving you some tips about how to incorporate CDI in an existing Java EE 6 application, I want to talk about injection. Yes, pure injection or how to inject a bean into another one. As you’ll see in this series of three articles (Part II), many different cases can happen. Let’s start with a simple one : a straight forward injection.

Default injection

The simplest possible injection case is… simple. You have something, and you inject something into it. Why am I using the word something ? Because until Java EE 5 we could only inject resources (EntityManager, Datasource, JMS destinations and factories…) into certain components (EJBs and Servlets). With CDI, you can inject nearly anything into anything else.

Versions of software used for this arcticle
Java SE 1.6.0_23
GlassFish 3.1
Maven 3.0.2

To illustrate injection I’ll be using the same use case I’ve used in previous articles or in my Java EE 6 book : a CD-Book store.

The class diagram above shows the following components :

  • Book is just an Entity with some attributes and named queries
  • ItemEJB is a stateless EJB (with no interface) doing CRUD operations on the Book thanks to the EntityManager
  • IsbnGenerator is just a POJO that generates a random ISBN number (used for the Book)
  • ItemRestService is annotated with @Path (which designates a REST web service in JAX-RS) and delegates the CRUD operation to the ItemEJB
  • ItemServlet is a Servlet that uses the ItemEJB to display all the books from the database

As you can see, except for the EntityManager that is injected with @PersistenceContext, all the other components use @Inject. Here is a few lines of code of the ItemEJB getting a reference of the EntityManager :

@Stateless
public class ItemEJB {

    @PersistenceContext(unitName = "cdiPU")
    private EntityManager em;
    ...
}

The ItemServlet and the ItemRestService are very similar as they both inject a reference of the ItemEJB and the IsbnGenerator :

@WebServlet(urlPatterns = "/itemServlet")
public class ItemServlet extends HttpServlet {

    @Inject
    private IsbnGenerator numberGenerator;

    @Inject
    private ItemEJB itemEJB;
    ...
}

And the IsbnGenertor has absolutely nothing special to it as it doesn’t extends from anything nor it is annotated, it’s just a POJO :

public class IsbnGenerator {

    public String generateNumber () {
        return "13-84356-" + Math.abs(new Random().nextInt());
    }
}

In all these cases there is only one implementation to choose from (there is only ItemEJB, only one IsbnGenerator). If you only have one implementation, CDI will be able to inject it. We then talk about default injection. In fact, the code :

@Inject IsbnGenerator numberGenerator

could have been written

@Inject @Default IsbnGenerator numberGenerator

@Default is a built in qualifier that informs CDI to inject the default bean implementation. If you define a bean with no qualifier, the bean automatically has the qualifier @Default. The following code is identical to the previous one.

@WebServlet(urlPatterns = "/itemServlet")
public class ItemServlet extends HttpServlet {

    @Inject @Default
    private IsbnGenerator numberGenerator;
    ...
}

@Default
public class IsbnGenerator {

    public String generateNumber () {
        return "13-84356-" + Math.abs(new Random().nextInt());
    }
}

If you only have one implementation of the IsbnGenerator to inject, the default behaviour applies and a straight forward @Inject does the job. But sometimes you have to choose between several implementations, that’s where qualifiers come into play.

In this article I use the term bean, but to be more precise I should say managed bean (ie beans that are managed by CDI). ManagedBeans have been introduced in Java EE 6.

Ambiguous injection & Qualifiers

For a given bean type, there may be multiple beans which implement the type. For example, our application can have two implementations of the NumberGenerator interface : IsbnGenerator generates a 13 digits number and IssnGenerator a 8 digits number. A component that needs to generate a 13 digits number needs some way to distinguish between the two implementations. One approach would be to explicitly specify the class (IsbnGenerator) but that creates a hard dependence between the component and the implementation. Another approach would be to rely on external XML configuration to declare and inject the appropriate bean. CDI uses qualifiers, which are annotations, to get strong typing and loose coupling.

In this article I’m using injection on the attribute, meaning that the @Inject annotation is on the attribute. But with CDI you can also use setter injection or constructor injection.

Let’s say, for some reason, that the ItemServlet creates books with a 13 digits ISBN number, and the ItemRestService creates books with a 8 digits ISSN number. Both (the ItemServlet and the ItemRestService) inject a reference of the same NumberGenerator interface, which implementation will there use ? You don’t know ? CDI doesn’t know either, and this is the kind of error message you will get :

Ambiguous dependencies for type [NumberGenerator] with qualifiers [@Default] at injection point [[field] @Inject private ItemRestService.numberGenerator]. Possible dependencies [[Managed Bean [class IsbnGenerator] with qualifiers [@Any @Default], Managed Bean [class IssnGenerator] with qualifiers [@Any @Default]]].

That means we need to be less ambiguous and tell CDI which bean to inject where. If you come from Spring the first thing that comes to your mind is “let’s use the beans.xml file“. But as this post says, “beans.xml is not there to define beans in XML“. With CDI you use qualifiers (annotations).

There are three built-in qualifiers in CDI :

  • @Default : If a bean does not explicitly declare a qualifier, the bean has a @Default qualifier
  • @Any : allows the application to specify qualifiers dynamically
  • @New : allows the application to obtain a new qualified bean

A qualifier represents some semantic associated with a type that is satisfied by some implementations of the type. For example, you could introduce qualifiers to represent thirteen digits number generator or eight digits number generator. In Java qualifiers are represented by annotations defined as @Target({FIELD, TYPE, METHOD}) and @Retention(RUNTIME). It is declared by specifying the @javax.inject.Qualifier meta-annotation as follow :

@Qualifier
@Retention(RUNTIME)
@Target({FIELD, TYPE, METHOD})
public @interface EightDigits {
}

@Qualifier
@Retention(RUNTIME)
@Target({FIELD, TYPE, METHOD})
public @interface ThirteenDigits {
}

As you can see, I’ve just defined two qualifiers, very easily. Right, so how do I use them now ? Better than words, a class diagram will make it clear.

First of all, the qualifiers need to be applied on the appropriate implementation. As you can see, @ThirteenDigits is applied to IsbnGenerator and @EightDigits to @IssnGenerator :

@EightDigits
public class IssnGenerator implements NumberGenerator {

    public String generateNumber() {
        return "8-" + Math.abs(new Random().nextInt());
    }
}

@ThirteenDigits
public class IsbnGenerator implements NumberGenerator {

    public String generateNumber() {
        return "13-84356-" + Math.abs(new Random().nextInt());
    }
}

Then, the components that inject a reference to the NumberGenerator interface also need to use it as follow :

@WebServlet(urlPatterns = "/itemServlet")
public class ItemServlet extends HttpServlet {

    @Inject @ThirteenDigits
    private NumberGenerator numberGenerator;
    ...
}

@Path("/items")
@ManagedBean
public class ItemRestService {

    @Inject @EightDigits
    private NumberGenerator numberGenerator;
    ...
}

You don’t need external configuration, that’s why CDI is said to use strong typing. You can rename your implementations to whatever you want, the injection point will not change (that’s loose coupling). Note that a bean may declare multiple qualifiers. As you can see, CDI is an elegant way to have typesafe injection. But if you start creating annotations each time you need to inject something, your application will end up being very verbose. That’s when enumerations can help you.

Qualifiers with enumerations

Each time you need to choose between implementation you create an annotation. So if you need an extra two digits number generator or a ten digits number generator you create more and more annotations. Looks like we are moving from XML Hell to Annotation Hell ! One way to avoid the multiplication of annotations is to use enumeration as follow :

@WebServlet(urlPatterns = "/itemServlet")
public class ItemServlet extends HttpServlet {

    @Inject @NumberOfDigits(Digits.THIRTEEN)
    private NumberGenerator numberGenerator;
    ...
}

@Path("/items")
@ManagedBean
public class ItemRestService {

    @Inject @NumberOfDigits(Digits.EIGHT)
    private NumberGenerator numberGenerator;
    ...
}

@NumberOfDigits(Digits.THIRTEEN)
public class IsbnGenerator implements NumberGenerator {

    public String generateNumber() {
        return "13-84356-" + Math.abs(new Random().nextInt());
    }
}

@NumberOfDigits(Digits.EIGHT)
public class IssnGenerator implements NumberGenerator {

    public String generateNumber() {
        return "8-" + Math.abs(new Random().nextInt());
    }
}

As you can see I got rid of the @ThirteenDigits and @EightDigits qualifiers and I’m using the single qualifier @NumberOfDigits which as an enumerations as a value (in my example @EightDigits). This is the code you need to write :

@Qualifier
@Retention(RUNTIME)
@Target({FIELD, TYPE, METHOD})
public @interface NumberOfDigits {
    Digits value();
}

public enum Digits {
    TWO,
    EIGHT,
    TEN,
    THIRTEEN
}

Conclusion

I don’t know about you, but I love it. I really like the way CDI wires beans together without XML, just with pure Java in a type-safe way. Ok, ok, I admit, not everything is beautiful. The first thing I see is the multiplication of annotations in your code. Thanks to enumerations, this can be limited. The other point I can see is the IDE support. Your IDE needs to be cleaver to know that :

@Inject @NumberOfDigits(Digits.EIGHT) NumberGenerator numberGenerator

refers to IssnGenerator. But here I’m talking without really knowing much about the topic. I use Intellij IDEA and the CDI support is just amazing. I can navigate from bean to bean without worrying about knowing the implementation. I suppose NetBeans might have some kind of support… but I wonder if Eclipse does ;o)

The next article will cover the different available injection points, so stay tuned.

Download

Download the code, give it a try, and give me some feedback.

References