Injection with CDI (Part I)
Join the DZone community and get the full member experience.
Join For Free 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 two articles , 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 :
@stateless public class itemejb { @persistencecontext(unitname = "cdipu") private entitymanager em; ... }
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 :
could have been written
@inject 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.
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 :
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 :
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 :
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 :
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 :
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 :
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 alternatives and producers , so stay tuned.
download
download the code , give it a try, and give me some feedback.
references
Opinions expressed by DZone contributors are their own.
Trending
-
Competing Consumers With Spring Boot and Hazelcast
-
Extending Java APIs: Add Missing Features Without the Hassle
-
From On-Prem to SaaS
-
Essential Architecture Framework: In the World of Overengineering, Being Essential Is the Answer
Comments