There Can Only Be One

An Introduction to CDI

NicolasFrankel
An-Introduction-to-CDI

Nicolas Frankel introduces us to contexts and dependency injection.

I’m convinced a technology should
embrace standards when possible. Regarding Dependency Injection,
the market regards Spring as a de facto standard. However, it is
competing with other products, like Google Guice for example. It
makes my work as an architect harder since my craft is to devise
the most durable solutions: standards are my allies in achieving
this goal.

CDI, formerly known as JSR 299, is
an attempt at describing a true standard on Dependency Injection.
What makes CDI appealing at first glance is that both SpringSource
and Google took a seat in the specifications team. CDI is a part of
the Java EE 6 stack, meaning an application running in a Java EE 6
compatible container can leverage CDI out-of-the-box, at least on
paper. Thus, for a Maven application, all that is required is to
add the following dependency:

The Basics

How is it done? Let’s take a simple example. Should one want to
use a lighweight service layer, one just needs a reference to such
a service in one’s servlet. In order to do that, just add a
reference to the service as an attribute and annotate it with
@Inject:

Note for Guice users: notice this is the same annotation, only
in a standard package (javax.enterprise). That’s all! No fancy XML
configuration, no JNDI resource to use, no nothing. The only thing
to do is to follow what can be called the Highlander rule: There
can be only one. This rule enforces that there must be one and only
one class on the classpath that extends HelloService, thus
fulfilling the interface contract. This is common sense: the
injection must be deterministic and it cannot if CDI has more than
one implementation to choose from.

Activation


In truth, just using the @Inject
annotation, one probably will be faced by a NullPointerException.
For CDI to activate, one needs to have a XML configuration file
named beans.xml under WEB-INF for web applications or META-INF for
jars. This file can be empty but is mandatory in order for CDI to
bootstrap.

 

Qualifiers


Yet, such conditions are not met
most of the time since one will probably have at least another mock
implementation for integration tests. A concept is missing
somewhere: it is the qualifier. Qualifiers add a quality to
injection so that the Highlander rule is enforced between all
classes that meet all the injection qualifiers. Thus, one can add a
distinguishing qualifier to the mock service to resolve our
quandary. Let’s design such a qualifier:

 

• to be considered a qualifier, it
uses the @Qualifier annotation

• since injection is done at
runtime, the retention policy must be runtime

• target will be type, since it’s
the class itself that will be annotated

The result is the following:

Just annotate your mock service with @Mock and
presto, the injection will succeed again. We haven’t seen how to
inject the mocked service, but please bear with me, it will be
adressed later.

Setter injection

In fact, this situation should not really happen (at least when
using Maven), since standard classpath and testing classpath should
be different. Moreover, unit testing should not use injection.

This would slightly change the servlet to be used both in
standard context and unit testing context: one will need to be able
to inject in the former case and to set it manually in the latter.
This is not a problem, since CDI also accepts setter injection like
in the following snippet:

More qualifiers

As we saw, the qualifier use-case from above was not a good
example. A much better one would be the need for a servlet to
report an error. There are many ways of reporting this: mail, log,
SMS, etc. The service used to report would be dependent of the
servlet, meaning all the services should be available on the
classpath. Now, as we have seen previously with @Mock, each service
would be annotated with @Mail, @Log, @SMS, etc. What we did not see
is how to inject the right service. Nothing could be easier, one
just has to tell CDI which service one needs by providing the
needed qualifier:

When not defining any qualifier, CDI will use one under the
cover, @Default. That’s why just annotating the mock service with
@Mock succeeded: the real service was annotated implicitly with
@Default and that was enough to fulfill the Higlander rule.

Qualifiers with attributes

Using the previous method will likely lead to an exponential
proliferation of qualifiers that contradict Java EE 6’s goals of
readibility and maintainability. CDI still lets us reach those
goals with annotation members. Now, the classes are:

Creating another reporting service
consists of creating the service implementation itself and adding a
value to the enumeration.

 

Singletons


Traditionally, services are
stateless and, as such, have little interest in being instantiated
more than once: it’s a good practice to make them singletons.
Frameworks such as Spring make container-managed beans singletons
as a default. Singletons creation is a feature of CDI but beware
that singletons should be explicitly marked as such:

 

 

Scoped beans


Singletons are only a particular
case of a scope. In Java EE, scopes are well-defined regarding web
applications: application, session, request and page. CDI does not
manage page scope and adds a conversation scope that is tied to
JSF. Scope usage in CDI is similar as Spring: injected bean will be
tied to the defined scope and its visibility is restricted to that
scope. Information relative to settings and preferences could well
take place in a session-scoped bean for instance. Just add the
right scope annotation to this bean:

At this point, one should probably
be able to address 80% of one’s needs. Nonetheless, CDI goes
further.

 

Producers


Previous examples cannot resolve all
our use-cases. Some of these include:

• injection of random values

• injection of context-dependent
value

• in general, places where the
injection process cannot be narrowed down to a simple new()

 

These hint at a very well-known
pattern, the factory. Factories are implemented in JSR-299 as
producers. Let’s take a simple example, the injection of a
connection from a data source. The code that gets the connection
either creates it with a direct connection to the database or
retrieves it from a data source pool. In the latest case, the
following code would fit:

 

     
   

Interceptors


With Java EE 6, we can harness the
power of AOP without AOP. Like in the previous example, using
interceptors is very straightforward. There are 3 steps. Let’s
implement a simple timer, for benchmarking purposes. The first step
is the declaration of the interceptor. To do so, just use the
@InterceptorBinding:

The second step is the interceptor implementation. It uses the
@Interceptor annotation, coupled with the previously defined
one:

Notice:

• the method annotated with @AroundInvoke returns an Object

• it uses a parameter of type InvocationContext

The last step is to declare such interceptors in
WEB-INF/beans.xml because interceptors are deactivated by
default.

The beans.xml also tells the
container about how to order the interceptors in case there is more
than one. There are two other interceptor types, @PostConstruct and
@AroundTimeout (for EJB).

 

Decorators


Decorators – guess what – implement
the Decorator design pattern. They are very similar to interceptors
with two interesting differences:

 

• a decorator must implement the
interface it is decorating (and yet can be abstract, so it does not
have to implement the methods)

• a decorator can have a reference
to the object it decorates.

 

It is done through injection Like
interceptors, they must be referenced in the beans.xml file in
order to be activated. Let’s take a simple example and create an
interface which contract is to return an HTML representation of an
object:

 

Now we need a date class that knows
its HTML representation. I know the design is quite bad but bear
with me, it’s just an example. Should one want a decorator that
puts HTML inside <strong> tags, here’s the way:

Observers


CDI also implements the Observer design pattern, thus at last
enabling simple event-driven development paradigm on the Java EE
platform. The basis for it is the event type. An event type is a
simple POJO. The Observer is also a POJO: in order for a method of
the Observer to be called when an event is fired, just add a
parameter of the right event type and annotate it with
@Observes:

On the other side, the event producer should have an attribute
of type javax.enterprise.Event parameterized with the same event
type. In order to fire the event, call event.fireEvent() with an
event instance:

Now, when sending a POST request to
the servlet, the after- PostEvent() method of the
EventObserverService will be called.

 

Alternatives


Previously, mock service was
addressed by calling the setter and passing a newly created
instance “by hand”. This is all fine and well in a unit testing
case, but we also want to manage integration testing. The situation
is thus the following:

 

• there are two implementations of
the same interface on the classpath

• one cannot change the servlet code
(for example, add a qualier to the service attribute)

 

Given the deterministic nature of
CDI, we should basically be toast. In fact, nothing could be
further from the truth. Just use the @Alternative annotation and
CDI will conveniently ignore the annotated class.

 

What’s the point then to create it
in the first place? Remember the unused-till-then beans.xml from
above. It will come to our aid, since it accepts
<alternative> tags. These tags activate the alternatives.

As such, one could have two beans.xml:

• a basically empty standard context

• and another integration testing context full of
alternatives

Platform

This article was written with GlassFish v3, which uses Weld
v1.0.1, as a platform. Weld is CDI reference implementation, and
also a part of the Seam framework.

Conclusion

This article only brushes the surface of CDI. Nevertheless, it’s
an attempt at standardization and looks very promising. To go
further:

Commons annotations (JSR-250) page: Commons
annotations has annotation for DI in Java (@Resource)

CDI (JSR-299) page: amazingly enough, CDI is
about DI in Java EE

Weld’s documentation: Weld is CDI JBoss
implementation and also the reference implementation

• Article on the merits of JSR-299 compared to the merits of JSR-330

Author
NicolasFrankel
Nicolas Frankel comes from a rather unorthodox background, since he holds MSc in both Architecture and Civil Engineering. Now a Sun Certified professional, he operates as a successful Java/Java EE architect with more than 10 years of experience in consulting for different clients. Based in France, he also practices (or practiced) as WebSphere Application Server administrator, certi ed Valtech trainer and part-time lecturer in different French universities, so as to broaden his understanding of software craftmanship. His interests in computer software are diversi ed, ranging from Rich Client Application, to Quality Processes via Open Source Software. When not tinkering with new products, or writing blog posts, he may be found practicing sport: squash, kickboxing and ski at the moment.
Comments
comments powered by Disqus