DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
  1. DZone
  2. Testing, Deployment, and Maintenance
  3. Testing, Tools, and Frameworks
  4. CDI - An Overview: Part 2

CDI - An Overview: Part 2

Nicolas Fränkel user avatar by
Nicolas Fränkel
CORE ·
Jun. 01, 10 · Interview
Like (0)
Save
Tweet
Share
10.14K Views

Join the DZone community and get the full member experience.

Join For Free

In the previous part of CDI, we saw some injection, qualifiers and scope. Now, it’s time to browse through more advanced features.

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:

public @interface FromDataSource {}

public class ConnectionProducer {

@Produces @FromDataSource
public Connection getConnection() throws Exception {

Context ctx = new InitialContext();

// Read the data source name from web.xml
String name = ...

DataSource ds = (DataSource) ctx.lookup(name);

return ds.getConnection();
}
}

Interceptors

With Java EE 6, you 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:

@InterceptorBinding
@Retention(RUNTIME)
@Target({METHOD, TYPE})
public @interface Benchmarkable{}

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

@Benchmarkable @Interceptor</pre>
public class BenchmarkInterceptor {

@AroundInvoke
public Object logPerformance(InvocationContext ic) throws Exception {

long start = System.currentTimeMillis();

Object value = ic.proceed();

System.out.println(System.currentTimeMillis() - start);

return value;
}
}
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.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
<interceptors>
<class>ch.frankel.blog.weld.BenchmarkInterceptor</class>
</interceptors>
</beans>

The beans.xml also tells the container about how to order the interceptors in case they 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:

public interface Htmlable {

String toHtml();
}

Now I need a date class that knows its HTML representation. I know the design is quite bad but bear with me.

public class HtmlDate extends Date implements Htmlable {

public String toHtml() {

return toString();
}
}

If I want a decorator that puts the HTML inside <strong> tags, here’s the way:

@Decorator
public class StrongDecorator implements Htmlable {

@Inject @Delegate @Any
private Htmlable html;

public String toHtml() {

return "<strong>" + html.toHtml() + "</strong>";
}
}

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:

public class EventObserverService {

public void afterPostEvent(@Observes PostEvent event) {

... // Do what must be done
}
}

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:

public class WeldServlet extends HttpServlet {

@Inject
private Event<PostEvent> event;

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

event.fire(new PostEvent());
}
}

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

Alternatives

In the previous article, I adressed the mock service with calling the setter and passing a newly created instance “by hand”. This is all fine and well in a unit testing case, but I also want to manage integration testing. The situation is thus the following:

  • there are two implementations of the same interface on the classpath
  • you can’t change the servlet code (for example, add a qualifier to the service attribute)

Given the deterministic nature of CDI, you 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.

@Report(MAIL) @Alternative
public class MockMailReportServiceImpl implements ReportService {
...
}

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 help, since it accepts <alternative> tags. These tags activate the alternatives.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
<alternatives>
<class>ch.frankel.blog.weld.service.MockMailReportServiceImpl</class>
</alternatives>
</beans>

As such, you could have two beans.xml:

  • a basically empty standard context
  • and another integration testing context full of alternatives

Platform

Seam logoGlassFish v3 logoThis 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.

I had no problems using the platform overall, yet, I couldn’t make alternatives, interceptors and decorators work. Strangely enough, all three must be configured in the WEB-INF/beans.xml. I do not know if I did something wrong or if there’s a bug in the current implementation though.

Conclusion

This 2-parts article only brushes at the surface of CDI. Nevertheless, IMHO, it looks very promising and I wish it much success.

To go further:

  • CDI, an overview – part 1
  • 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

 

From http://blog.frankel.ch/cdi-an-overview-part-2

CDI

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Cucumber.js Tutorial With Examples For Selenium JavaScript
  • Apache Kafka Is NOT Real Real-Time Data Streaming!
  • 3 Main Pillars in ReactJS
  • 7 Most Sought-After Front-End Frameworks for Web Developers

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: