Bringing Real Dependency Injection to the Platform

How To Use DI in Java EE 6

Antonio Goncalves
How-to-Use-DI-in-Java-EE-6

In this article, Java Champion Antonio Goncalves looks at using the new dependency injection model brought by Contexts and Dependency Injection.

Java EE 6 is over a year old now. With this new version of the Enterprise Edition came some improvements to the existing specifications (EJB 3.1, JPA 2.0, JSF 2.0…) but also completely new ones (JAX-RS, Bean Validation and CDI). This article is about how to use the new dependency injection model brought by Contexts and Dependency Injection.

Dependency Injection (DI) is a design pattern that decouples dependent components. It is a specific form of inversion of control, “where the concern being inverted is the process of obtaining the needed dependency”. The term was first coined by Martin Fowler.

Java is an object-oriented programming language, meaning that the real world is represented using objects. A Book class represents a copy of “H2G2″, a Customer represents you and a PurchaseOrder represents you buying this book. These objects depend on each other: a book can be read by a customer and a purchase order refers to several books. This dependence is one value of object-oriented design.

For example, the process of creating a purchase order (OrderService) can be reduced to printing the PO (PrintingService), writing and sending an email to the customer (EmailService) and delivering the books to the customer (DeliveryService). The EmailService can be as simple as “writing a message and sending it to an email address” or more complex such as “writing a message body, a subject, adding bold/italic/underlying to the message, checking spelling, validate the email address and sending the message to the valid email address”. The OrderService would end up depending either on a SimpleEmailService or a RichEmailService according to some condition or environment. How would you connect an OrderService to an EmailService ? One solution is to use the good old new operator:

This is simple and does the job. But what if I want to choose between implementations and not just get stuck with Simple-EmailService ? One solution is to pass the implementation to the constructor and leave the external services to choose which implementation they want to use:

 

So now an external component could use the OrderService with the implementation it needs:

This illustrates what inversion of control is : the control of creating the dependency between OrderService and EmailService is inverted because it’s given to an external component, not the component itself.

 

Since you end up connecting the dependencies yourself this technique is referred to as construction by-hand. In the code above we used the constructor to choose implementation (constructor injection) but another common way is to use setters (setter injection). Instead of constructing the object dependency graph by hand you can use a Factory. This Gang of Four (GoF) design pattern offloads the burden of creating dependencies and assembling objects to a third party (called a factory).

 

One way or the other, you end-end writing some code. With Java EE being a managed environment you don’t need to construct by hand nor use a factory, but instead leave the container to inject a reference for you. One way to think about a DI in a managed environment is to think of JNDI turned inside out. Instead of an object looking up other objects, the container injects those dependent objects for you. This is the so-called Hollywood Principle, “Don’t call us?” (lookup objects), “we’ll call you” (inject objects).

 

Dependency Injection in Java EE


Java EE was created in the late 90’s (it was then called J2EE). The first version already had EJBs, Servlets, JMS and so on. From there, each new version added extra specifications (Web Services, JSF…), to reach the number of 28 specifications for Java EE 6. Dependency injection, which was a common concept in other frameworks, arrived in Java EE 5. But it was limited and could be seen as resource injection as you could only inject certain resources (JDBC DataSource, JMS factories or destinations, and JPA Entity Manager) and services (TimerService, User Transaction, Web Services, EJBs) to certain components (mostly EJBs and servlets). It allowed you to simplify component dependencies and let the EJB container deal with the complexities of managing the life-cycle of the resource (instantiating, initializing, sequencing and supplying resource references to clients as required). It is the responsibility of the container to inject a reference to a resource based on the dependency declaration.

 

This first step taken in Java EE 5 wasn’t enough so two brand new specifications were created in Java EE 6 to bring real dependency injection to the platform and also to bring real consistency between specifications: Dependency Injection (JSR 330) and Contexts & Dependency Injection (JSR 299).

 

DI and CDI both in Java EE 6


These two specifications are complementary and can’t be used one without the other.

Dependency Injection for Java (aka @Inject) defines a set of annotations (@Inject, @Named, @Provider, @Qualifier, @Scope and @Singleton) mainly used for injection. If you download this JSR (which is actually just Javadoc) and read through it, you will be surprised to see that no semantic is defined (i.e. the injection behaviour is not portable across implementation). This specification is implemented in Spring 3, Guice, and also in Java EE 6 with CDI. You will find the DI annotations in the javax.inject package.

 

Contexts and Dependency Injection gives semantic to JSR 330 and adds more features such as context management, events, decorators and enhanced interceptors (AOP). Further more, CDI allows to extend the platform in a standard way, which was impossible until now. The aim of CDI was to fill all these gaps : give more cohesion to the platform, knit together the web tier and the transactional tier, turn dependency injection into a first class citizen and have the ability to add new extensions easily. DI and AOP are the foundation of many Java frameworks, and CDI could be the foundation of future frameworks or even JSRs. The reference implementation is Weld, an open source project from JBoss. You will find the CDI annotations and classes in the javax.enterprise.inject package.

 

In a nutshell, dependency injection is the ability to inject components into an application in a typesafe way (yes, typesafe way, which means no XML !), and contexts is the ability to bind the life-cycle and interactions of stateful components to well-defined life-cycle scopes. This article concentrates on the DI part.

 

Default Injection


Injection already existed in Java EE 5 with the @Resource, @PersistentUnit or @EJB annotations for example. But it was limited to certain resources (datasource, EJB…). With DI you can inject nearly anything (we call that “managed beans”, which are beans managed by CDI) anywhere thanks to the @Inject annotation. Note that in Java EE 6 you can still use the other injection mechanisms (@Resource…) but you should consider using @Inject from now on.

 

To take the previous example, here is how you would inject a reference of the SimpleEmailService into the OrderService :

 

As you can see, a simple @Inject annotation on the property (or on the setter or constructor) will inform the container that it has to inject a reference into emailService. If you only have one implementation, CDI will be able to inject it. We then talk about default injection. In fact, the code @Inject SimpleEmailService emailService could have been written @Inject @Default SimpleEmailService emailService. @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.

 

If you only have one implementation of a bean 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.

 

I first mentioned that no XML was needed in CDI. Well, it’s not completely true. To make CDI work you need a beans.xml file in your classpath (in the META-INF or WEB-INF directory). The good news is this beans.xml file is usually totally empty (except for alternatives as you’ll see later). This file tells CDI to discover beans (aka bean discovery) in the application.

 

      

Ambiguous Injection and Qualifiers

 

For a given bean type, there may be multiple beans which implement the type. Coming back to our example, a component can choose between two implementations (SimpleEmailService or RichEmailService) of the interface EmailService. How do you make the choice? Most frameworks heavily rely on external XML configuration to declare and inject beans. CDI uses qualifiers, which basically are annotations. That’s how type safe injection comes into play (strong typing).

 

Coming back to the previous code, as you saw, it will work if you only have one implementation, but if you try to run it with more than one implementation of the interface EmailService, this is the kind of error that you will get :

 

 

The injection is ambiguous, CDI doesn’t know which bean to inject (either SimpleEmailService or RichEmailService). It needs some way to distinguish between the two different managed beans. One approach would be for the client to explicitly specify the class that implements the EmailService interface. However, this approach creates a hard dependence (strong coupling) between client and implementation. To have loose coupling and strong typing, CDI uses qualifiers.

 

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 rich or simple email service. In Java code, qualifier types are represented by annotations that you apply to a managed bean defined as @Target({FIELD, TYPE, METHOD}) and @Retention(RUNTIME). It is declared by specifying the @javax.inject.Qualifier meta-annotation as follow:

As you can see, the code above is quite simple: two annotations annotated with Qualifier. These qualifiers are then applied to injection points to distinguish which implementation is required by the client. In Listing 1 the OrderService explicitly defines which implementation by injecting a reference of the @Rich EmailService.

 

If you run this code you will not have any ambiguous dependency any more as CDI knows exactly which implementation of the managed bean to inject. You could even rename the RichEmailService class to RichMailerService and the code will work with no other change as CDI relies on the name of the qualifier, not the name of the implementation (that’s loose coupling in action). Note that any bean may declare multiple qualifiers.

Choosing implementation at development time is very useful, but sometimes you need to choose at deployment time. That’s when you can use alternatives.

Alternatives

As you’ve just seen, when you have more than one version of a bean that you use for different purposes, you can choose between them during the development phase by injecting one qualifier or another. Qualifiers let us choose between multiple implementations of an interface at development time. But sometimes you want to inject an implementation depending upon the deployment environment. For example, you may want to use a mock email service in a testing environment. This is possible with alternatives and a bit of XML.

Alternatives are beans whose implementation is specific to a particular deployment scenario. They are annotated with the special qualifier javax.enterprise.inject.Alternative. This is what an alternative to the rich email service could look like:

As you can see the MockEmailService implements the EmailService interface as usual. It is both annotated with @Alternative and @Rich, meaning that this managed bean is an alternative to the RichEmailService. By default, @Alternative beans are disabled and you need to explicitly enable them in the beans.xml descriptor.

 

 

Now if you execute the application with the following code with the beans.xml file, the OrderService will get injected the MockEmailService rather than the RichEmailService.

 

 

If the <alternatives> element is commented out in the beans.xml file, the RichEmailService class is used. You can have several beans.xml file declaring several alternatives depending on your environment (development, production, test…).

 

If you think of qualifiers being an aggregation of annotations, then you can refactor your code and create a @Mock qualifier which is an @Alternative and a @Rich email service. You will then get the following code :

Now you can go back to the MockEmailService and change it to being a @Mock. The behaviour is exactly the same as having @Alternative and a @Rich together in the same managed bean:

@Inject, alternatives and qualifiers allow you to have a flexible and type-safe injection model. But the beauty of it is that you can use this exact injection model in most of Java EE 6 components.

 

Inject Everything Everywhere


Java EE 5 was about injecting resources (Datasource, JMS factories…) to certain components (mostly EJBs). Java EE 6 is about injecting nearly everything (or so called managed beans) to nearly all the components. So far you’ve seen plain old Java objects (POJOs) injecting other POJOs. But you can inject an EJB into a Servlet or a RESTful Web Service. Below you can see a servlet injecting our rich email service as well as an EJB that deals with orders. As you can see, the @Inject annotation is used exactly the same way in both cases :

Bootstraping CDI in Several Environments


Both JSRs 299 and 330 are included in Java EE 6 as well as the Web Profile 1.0 (which is a subset of the entire platform). This means you don’t have to do any extra work to use injection in a Servlet 3.0 or EJB 3.1 container. It works out of the box. But the beauty of CDI is that it doesn’t require Java EE 6. You can use CDI with simple POJOs in a Java SE environment, as well as some Servlet 2.5 containers (Tomcat 6.5 or Jetty). Of course, because it’s not built in, you’ll need a bit of configuration. And because this feature is not standard, each different environment will need its own configuration. But it then works fine and you can use all the previous examples within Tomcat 6.5 or even just with Java SE 6.

But There is More to CDI

Injection was already popular in other frameworks (PicoContainer, Spring, Guice) and it finally became a first class citizen in Java EE 6. But there is more to CDI that just dependency injection.

One of the key features of CDI is it knits together the web tier and the transactional tier (i.e EJBs). So the idea is to make a managed bean (POJO, EJB…) accessible through expression language (EL) and therefore be able to use it in JSF and JSP pages. For that, you just need to give your bean a name with the @javax.inject.Named built-in qualifier:

The @Named qualifier allows you to access the managed bean through its name (which by default is the class name with first letter in lower-case but you can override it with @Named(“MyEmailService”)). Then you can invoke an attribute (via its getter and setter) or a method straight in your JSF or JSP page. The following example shows a JSF page with an input text to enter the email body and a button to send the email :

 

Another interesting feature in CDI are scopes and contexts. The scope of a bean determines its life-cycle. Until now Java EE had stateless and stateful components which were not tight together (you couldn’t easily tight the life duration of a HTTP session to a stateful EJB for example). You had to twist built-in web scopes (request, session and application) to fit the back-end transactional layer. With CDI things are much easier and extensible.

 

CDI defines four built-in scopes and gives you extension points so you can create your own :

 

• @RequestScoped

• @SessionScoped

• @ApplicationScoped

• @ConversationScoped

 

The three first scopes are well known. For example, if you have a session-scoped bean, LoggedInUser, the RichEmailService that is called in the context of the same HttpSession will see the same instance of LoggedInUser. This instance will be automatically created the first time a LoggedInUser is needed in that session, and automatically destroyed when the session ends.

 

 

The conversation scope, however, is a new one that acts a bit like the session scope: it holds state associated with a user, spans multiple requests to the server but is demarcated explicitly by the application.

 

Conclusion

 

Dependency Injection (JSR 330) and Contexts & Dependency Injection (JSR 299) both bring a standard, portable and type safe support for dependency injection to Java EE 6. CDI adds extra features such as scopes and contexts but also enhanced interceptors, decorators and events. But the noble goal of CDI is to be a foundation for frameworks which will extend the platform and integrate with other technologies. Therefore, CDI exposes a set of SPIs for developers in order to create portable extensions. The Java EE platform becomes finally extensible in a standard way.

The good news is that you don’t need to use a Java EE 6 application server such as GlassFish 3.x or JBoss 6.x. You can bootstrap CDI in several environments and get all its benefits with your Servlet 2.5 container (Jetty or Tomcat 6.x) as well as your Java SE application. Being a standard, you can choose from several implementations (OpenWebBeans from Apache, Weld from JBoss or CanDI from Caucho) and get started with it now. Enjoy.

Author
Antonio Goncalves

Antonio Goncalves

All Posts by Antonio Goncalves

Antonio Goncalves is a senior software architect who has focused on Java development since the late 1990s. As a former BEA consultant he has great expertise in application servers such as WebLogic, JBoss, and GlassFish. He is particularly fond of open source and is a member of the OSSGTP (Open Source Solution Get Together Paris). He is also the co-creator and co-leader of the Paris Java User Group. Antonio has joined the JCP and was an Expert Member of various JSRs (Java EE 6, JPA 2.0, and EJB 3.1) and has joined today the Java EE 7 group. For the last few years he has given talks at international conferences mainly about Java EE, including JavaOne, The Server Side Symposium, Devoxx, Jazoon and many Java User Groups. He has also written numerous technical papers and articles. Since 2009, he has been part of the French Java podcast called Les Cast Codeurs (influenced by the Java Posse). For all his work for the Java Community, Antonio has been elected Java Champion.
Comments
comments powered by Disqus