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 articles (Part II, Part III), 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_33
GlassFish 3.1.2.2
Maven 3.0.3

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

About these ads
Comments
9 Responses to “Injection with CDI (Part I)”
  1. Nathan says:

    I tied to use weld cdi and didn’t have any luck. I am going to try and get your example working tonight and will let you know how it goes.

  2. Hi Antonio

    It is a beautiful sample, the idea om strong types goes right into perception.
    And I see that the sample is using maven, it is five stars extra

    Why I comment, I would like to see the sample written to a “main()” program. So we are out of containers.
    Okay – there is HTTP involved … so jetty will do.

    Having the sample running by command..
    mvn jetty:run
    Would be excellent.

    I’m not against containers, I am just for freedom
    Best regards
    Anders Kristian Andersen

  3. Brooke says:

    Hi Antonio,

    Clearly written article, thanks. Unfortunately I’m getting a 404 when trying to DL the code!

    Cheers,

    Brooke

  4. Optimus says:

    Hello!

    You said “With CDI, you can inject nearly anything into anything else”, but what about if I want to inject a @Transient field into a JPA Entity? This can be useful if you need, for example, to inject some external properties into the Entity. Is it possible?

  5. Arun says:

    Sir,

    I am a newbie to Dependency Injection in general and CDI in particular. So kindly bear with me for this stupid question.

    whats the difference between
    1) injecting a specific “qualifier” instance
    @Inject @EightDigits
    private NumberGenerator numberGenerator;

    Versus

    2) just instantiating like this
    private NumberGenerator numberGenerator = new IssnGenerator();

    That is with 1, at compile time, we are specifying what to inject. With 2, we are setting directly. Howz 1 better than 2?

Trackbacks
Check out what others are saying...


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 6,114 other followers

%d bloggers like this: