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.
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.
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.