Adding CDI to an existing Java EE 6 application

In my previous post I’ve shown you how to bootstrap CDI in several environments (GlassFish, Tomcat, Jetty, Java SE). So now let’s go a bit further and use it in real code. As its name states, CDI (Contexts and Dependency Injection) is also about Dependency Injection, so let’s focus on just this feature for now. I will not define what DI (Dependency Injection) is. If you don’t know I’ll leave you to check the definition, the origins of this pattern and even a book that covers it all.

Dependency Injection was introduces in  Java EE 5. Well, to be more precise it was resource injection, i.e. you could inject container resources such as EJBs, entity managers, data sources and JMS factories and destinations into a set of defined components (Servlets, JSF backing beans and EJBs). For this purpose Java EE 5 introduced a few annotations : @Resource, @PersistenceContext, @PersistenceUnit, @EJB and @WebServiceRef. But Java EE 6 goes way beyond by introducing two specifications :

  • Dependency Injection for Java (JSR 330) defines a set of annotations (@Inject, @Named, @Provider, @Qualifier, @Scope and @Singleton) mainly used for injection. If you download this JSR (which is actually javadoc) and read through it, you will be surprised to see that no semantic is defined (i.e. the behaviour is not portable across implementation, you could implement the injection mechanism you think is appropriate). This specification is implemented in Spring 3, Guice, and also in Java EE 6 with CDI
  • Contexts and Dependency Injection (JSR 299) gives semantic to JSR 330 and adds more features such as context management, events,  decorators, enhanced interceptors and extension mechanism.

This blog post is about adding CDI to an existing Java EE 6 application.

Use case

My previous post focused on bootstrapping CDI, so I didn’t care much about the business code, that’s why I used a Hello World scenario. This time let’s make it a bit more real. I took some code from my Java EE 6 book that you can find on GitHub. It’s about CRUD operations on a Book entity. Here are the components involved :

  • Book : an entity describing a book (title, ISBN number, price…)
  • ISBNGenerator : a managed bean to generate random ISBN numbers (you can see it as a helper class)
  • ItemEJB : a stateless EJB to have transactions for persisting, updating, removing, finding from a database
  • ItemRestService : a service that gives a RESTful interface to the EJB
  • ItemServlet : a servlet that uses the EJB to display a list of books

Injection without CDI

As I said earlier, resource injection was introduced with Java EE 5 and is still available in Java EE 6. Except for the Book entity, all the components of our use case are injectable using Java EE 6 resource  injection (i.e. without CDI). The class diagram below shows you the injection annotations (@Resource, @PersistenceContext and @EJB) used to make the entire thing work.

Some things to look carefully at :

  • @EJB is used to inject an EJB into the Rest web service and the servlet
  • In our example, @Resource is used to inject a javax.annotation.ManagedBean
  • ISBNGenerator needs to be a javax.annotation.ManagedBean to be injectable (Managed Beans were introduces in Java EE 6). If not, the container will not consider it as being a resource
  • @PersistenceContext injects an entity manager
  • ItemRestService is annotated with @Path (which is normal for a REST web service) but also with @ManagedBean. In fact, if a REST service wants to inject a EE resource (like an EJB) it needs to either be a @ManagedBean, @Stateless or @Singleton. In Java EE 7 all the components will be managed beans, so this double annotation would not be needed any more.

Injection with CDI

This Java EE 6 example works fine without CDI if you use resource injection. By adding CDI you will get a few enhancements that I will explain in future posts. But for now let’s just concentrate on how do you add CDI to an existing Java EE 6 application ? Very easily as I shown in my previous post, just add an empty beans.xml path to your application and this will bootstrap CDI. Then, just replace all the @Resource and @EJB with @Inject. You will get the following class diagram :

The code doesn’t change much :

  • You don’t need @EJB or @Resource anymore, just use @Inject
  • Because anything is injectable with CDI,  ISBNGenerator doesn’t need to be a managed bean but just a POJO.

Conclusion


As you can see, to add CDI to your existing Java EE 6 application you just need to add a beans.xml file, replace all @EJB and @Resource by @Inject and get rid of the @javax.annotation.ManagedBean. Well, you might think that there is not much interest in CDI if it’s only a few replace all in your code. But as you will see in my coming posts, by doing so you enter a new world : the context and dependency injection world.

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

10 thoughts on “Adding CDI to an existing Java EE 6 application

  1. Hello Antonio.
    Thanks a lot for this excellent post.

    I work on a small variation of your testcase: in mine, i delegate the data services (eg load, create, delete, etc…) to a DAO.
    Concretely this means the persistence context is no more injected into my ejb, but rather in my dao (this dao being in turn injected into my ItemEJB).

    Unfortunately, i dit not manage to make it work (with GF 3.1), even with the addition of a ManagedBean annotation 🙁

    @ManagedBean
    public class MyDao {
    @PersistenceContext(unitName=”myUnit”)
    protected EntityManager entityManager;
    }

    => entityManager is always null
    What’s wrong ? Is it a bug in GF ?

    My conclusion is that persistence units/contexts seem to be only injectable in to “standard” container-managed objects (such as EJBs, servlets, etc..), not on Pojo’s. Is it right ??

    Second question:
    is it possible to inject JPA resources (Persistence units/contexts) also using @Inject – like we can do for ejb’s ?

    Thanks in advance,

    Bernard
    (Belgium)

    1. A DAO should be a stateless session bean. If not, you need to manage the lifecycle of your entity manager (create it with an EntityManagerFactory, close is and so on) and you don’t want to do that in a managed environment (let the container do it).

      No, you can’t @Inject an EntityManager, you still need @PersistenceContext

  2. You can @Inject EntityManager if you care to @Produces them.
    That makes the client-side code more consistent and if you throw qualifiers in the mix, I think that is an overall elegant solution.

  3. Why do you need @PersistenceContext for Dependecny Injection in Model.

  4. Does a JAX-RS class need to be annotated with @ManagedBean annotation for injecting an EE resource (like an EJB etc) into itself even when CDI is enabled?

    1. Unfortunattely yes. The integration between CDI & JAX-RS is not totally done (JAX-RS was ready before CDI 1.0 was finished). Better integration planned in CDI 1.1 & JAX-RS 2.0

  5. When you say “all the components of our use case are injectable using Java EE 6 resource injection (i.e. without CDI)”, don’t you really mean “using Java EE 5 resource injection” ?

    1. @EJB and @Resource still exist in EE 6. It comes from EE 5, but still available in EE6.

Leave a Reply