Archive

Posts Tagged ‘CDI’

Further into CDI

July 13th, 2010 Nicolas Frankel 2 comments

In one of my latest articles on CDI, one of the lessons I learned was to use factory methods in order to reduce the number of classes. In this article, I will go into the detail since I think it is of some importance. More basic informations on CDI can be found in some previous posts: overview part 1 and overview part 2.

The naive approach

During school, you were probably taught to create a class for each component. For example, if your application has 4 buttons, North, East, South and West, you’ll have 4 classes. Each class configures its label, its icon and its action, either in the constructor or in some other method.

Note: in CDI, your can annotate such method with @PostConstruct in order for the container to call it just after the constructor.

This produces the following code, when taking Swing as an example:

public class NorthButton extends JButton {

  public NorthButton() {

    // Initializes label
    // Initializes icon
    // Initializes action
  }

  ...
}

Common behaviour and attributes may be factorized into one superclass, thus you end up with 5 classes.

Using the right number of classes is very important in any object-oriented language:

  • If you use too few classes, you run the risk that each class you develop has too many responsabilities and are too big.
  • On the contrary, if you use too much classes, you’ll explode code into many places and it will be a maintenance nightmare. Moreover, in the Sun (Oracle ?) JVM, classes are loaded into the PermGen space which has a fixed size. Who has never seen the dreaded java.lang.OutOfMemoryError: PermGen space?

IMHO, both are good reasons not to create a single class for each instancied component.

The factory approach

The second logical step is to create methods that produce the right instance. In our previous example, that would mean a factory class, with 4 methods to produce buttons, one for each button and probably a 5th method with common behaviour:

public class ComponentFactory {

  @North
  @Produces
  public JButton createJButton() {

    JButton button = new JButton();

    // Set label
    // Set icon
    // Set action

    return button;
  }

  ...
}

Notice that you’ll still need an annotation for each single component:

@Retention(RetentionPolicy.RUNTIME)
@Target({FIELD,METHOD,PARAMETER,TYPE})
@Qualifier
public @interface North {}

In our case, that makes @North, @East, @South and @West. If these components are found throughout your application, fine (such as a Cancel button). If not, you still have a class for each component (annotations are transformed into classes at compile-time).

The “generic” annotations approach

CDI let you qualify injection not only from the annotation type but also from some (or all) their elements. We can thus greatly diminish the number of needed annotations. In order to do this, just create an annotation on this model:

@Retention(RetentionPolicy.RUNTIME)
@Target({FIELD,METHOD,PARAMETER,TYPE})
@Qualifier public @interface TypeName {

  Class value();

  String name(); }

Now the factory method becomes:

public class ComponentFactory {

  @TypeName(value = JButton.class, name = "North")
  @Produces public JButton createJButton() {

    JButton button = new JButton();

    // Set label
    // Set icon
    // Set action

    return button;
  }

  ...
}

Although this method meets our requirements regarding the number of classes (and annotations), it still has one major drawback: now, it’s the number of methods that is vastly increased. Though not nearly as great a disadvantage as a great number of classes, it makes the code less readable and thus less maintainable.

The fully “generic” approach

CDI let you use an injection point parameter for producer method. This parameter has much information about, guess what… the injection point. Such informations include:

  • the reflection object, depending on injection’s type, respectively Field, Method and Constructor for field, method parameter and constructor parameter injection
  • the required type to inject
  • annotations relative to the injection point

The latter point is what drives what comes next. It means you can annotate your injection point, then get those annotations during producer method execution. In our case, we could have an annotation for each attribute we want to set (text, icon and action). Let’s create such an annotation:

@Retention(RetentionPolicy.RUNTIME)
@Target({FIELD,METHOD,PARAMETER,TYPE})
public @interface Text { String value(); }

Such annotation could be used in the producer method in the following manner:

public class ComponentFactory {
  @Produces
  @TypeName(JButton.class)
  public JButton createJButton(InjectionPoint ip) {

    JButton button = new JButton();

    Annotated annotated = ip.getAnnotated();

    if (annotated.isAnnotationPresent(Text.class)) {

      Text textAnnotation = (Text) annotated.getAnnotation(Text.class);

      String text = textAnnotation.value();

      button.setText(text);
    }

    // Set icon
    // Set action

    return button;
  }
}

Now, the only thing you have to do is annotate your button field like so:

public class Xxx {

  @Inject
  @TypeName(JButton.class)
  @Text("North")
  private JButton northButton;

  ...
}

This will get us a button with “North” as label. And nothing prevents you to do the same with icon and action.

Morevover, with just text, you could go further and manage internationalization:

@Retention(RetentionPolicy.RUNTIME)
@Target({FIELD,METHOD,PARAMETER,TYPE})
public @interface Text {

  // Key in the properties file
  String value();

  // Path to the resource bundle
  String resourceBundle() default "path/to/resource/bundle";
}

This annotation could also be reused of other components that manage text, such as labels.

Conclusion

There’s no right or wrong approach in using CDI. However, the latter approach has the merit of being the most powerful. Additionally, it also let you write code relative to a component type in one single place. This is the road I’ve taken so far, and I’m very satisfied with it.

Categories: Java Tags:

Lessons learned from CDI in Swing

June 21st, 2010 Nicolas Frankel 4 comments

Sinced I dived into CDI, I explored classical Java EE uses. Then, I used CDI into a pet project of mine to see how it could be used in Swing applications. This article sums up what lessons I learned from itthis far.

Note: this article assumes you have some familiarity with CDI; if not, please read my previous articles on CDI (CDI an overview part 1 and part 2) or read the documentation.

In my last attempts at Swing (I’m more of a web developer), I figured it could be nice to configure most of the UI components in Spring rather than coding the parameters by hand. In doing this, I used the traditional XML configuration approach, since using annotations would couple my code to Spring JAR, something I loathe to do. With CDI, however, I can live with having my code tied to a standard API: I can change the implementation. This is akin to developing a servlet where you reference the Servlet API, then run it in any container you want.

I coded and coded this way, looked at things made, refactored, then code some more, just like when it’s a personal project and you have no deadlines to meet. Then, I realized I could learn some lessons I could put to good use for the future. Here they are, in no particular order.

The right JAR

Getting all the right CDI JARs for your Java SE project can be a rather daunting task. In order to ease your pain, Weld provides you with a all-in-one JAR aptly named weld-se. Don’t argue that it’s bloated and repackaged, just use it, you will save yourself a lot of pain. For Maven users, this is the configuration:

<project>
...
  <dependencies>
    <dependency>
      <groupId>org.jboss.weld</groupId>
      <artifactId>weld-se</artifactId>
      <version>1.0.1-Final</version>
    </dependency>
  </dependencies>
</project>

She’s an easy logger

All the log frameworks I know of (JDK, Commons Logging, Log4J and SLF4J) let you declare your class logger rather easily:

private static final Logger LOGGER = LoggerFactory.getLogger(MyClass.class);

Anyway, most of the time, in order to use this, you either:

  • create a template in your IDE. Yet configuring templates in each of your IDE can be rather tedious. Note to self: propose a feature where such templates (and preferences) could be saved on the web and shared across all of my IDE instances
  • copy the line from somewhere then paste it where you need it. Then you change the class to be logged. To be frank, and though it does not add to my legend (quite the contrary) this is what I do all the time

And doing the latter all the time, it happens I forget to change the logged class. Stupid, isn’t it? Perhaps, but what’s even more stupid is that I have to write it in the first place: the class is my context, it should be inferred. Guess what, Weld does it, with a little help from the weld-logger JAR (it uses SLF4J so beware or use the code as a template to use another framework):

@Inject
private Logger logger;

I truly don’t think it could be easier! The only drawback is that you lose the constant: for the projects I handle now, I can live with it. To use this feature, just add the following dependency to your POM:

<project>
...
  <dependencies>
    <dependency>
      <groupId>org.jboss.weld</groupId>
      <artifactId>weld-logger</artifactId>
      <version>1.0.1-Final</version>
    </dependency>
  </dependencies>
</project>

Remember initialization

CDI can of course inject your dependencies. But injecting your dependencies does not assemble them on the screen. Luckily, CDI also provides you with a hook in order to do it: this is the realm of the @PostConstruct annotation. Let’s take a very simple example:

public class MyPanel extend JPanel {

  @Inject
  private JCheckBox checkbox;

  @PostConstruct
  public void afterPropertiesSet() {

    setLayout(new FlowLayout());

    add(checkbox);
  }
}

The afterPropertiesSet() method is called after having injected all dependencies, and plays the role previously done in the constructor.

Note: yes, the method is named after an old Spring method defined in the InitializingBean interface, dating from version 1. It can now be replaced by specifying the init-method attribute of the bean in the XML beans definition file or using the @PostConstruct annotation.

(Don’t) grow in numbers

With CDI, your classes are injected into one another. However, this means that each component should have its own class. Tthis can be rather cumbersome: for buttons, for example, each should be attached its action on a specific basis. With time, even a moderately size application will grow in term of classs to be much bigger than a standard application. IMHO, this is not desirable since:

  • it makes your codebase bigger, and thus increase your development complexity
  • in Sun’s JVM, loading more classes mean you will use more PermGen space and you’re more likely to run into OutOfMemoryError

In order to limit the number of classes I produce, I used a component factory filled with producer methods. These methods are identified by CDI as injection providers.

public class ComponentFactory {

  @Produces
  public JButton getButton() {

    return new JButton();
  }
}

Use the injection point

This is good but not enough, since action (or text and icon) association will have to be done in the injected class. I would like to annotate the injected attribute with informations like the text of the button and get that information in my producer method. This is the goal of the InjectionPoint optional parameter. CDI provides it to you free of charge if you reference it in your method as a parameter.

public class ComponentFactory {

  @Produces
  public JButton getButton(InjectionPoint ip) {

    JButton button = new JButton();

    // Do something based on annotations on the parameter
    ...

    return button;
  }
}

This is exactly the way that Weld loggers (see above) are created.

Respect the Higlander rule

The Highlander rule is: “There can be only one”. Apart from being taken from a movie that young people mostly don’t know, it also enunciate a basic truth. Since injection must be deterministic, there cannot be two candidates for an injection point. Using producer methods as previously stated will run you into this problem: CDI will have both the JButton class and the producer method and will loudly complains about it in its usual way.

Exception in thread "main" org.jboss.weld.exceptions.DeploymentException: WELD-001409 Injection point has ambiguous dependencies.....
 at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:280)
 at org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:122)
 at org.jboss.weld.bootstrap.Validator.validateRIBean(Validator.java:141)
 at org.jboss.weld.bootstrap.Validator.validateBeans(Validator.java:331)
 at org.jboss.weld.bootstrap.Validator.validateDeployment(Validator.java:317)
 at org.jboss.weld.bootstrap.WeldBootstrap.validateBeans(WeldBootstrap.java:399)
 at org.jboss.weld.environment.se.Weld.initialize(Weld.java:81)
 at org.jboss.weld.environment.se.StartMain.go(StartMain.java:45)
 at org.jboss.weld.environment.se.StartMain.main(StartMain.java:57)

To be compliant with the Highlander rule, you’ll have to discard the JButton class as a candidate for injection. In order to do this, I used qualifiers, both on the injection point and on the producer method. Since I did not want a qualifier per injection point / producer method pair, I made it parameterizable:

@Qualifier
@Target( { FIELD, METHOD })
@Retention(RUNTIME)
public @interface JType {

  public Class<? extends JComponent> value();
}

Annotating both the injected attribute and the producer method with the JType annotation made my code compliant with the Highlander rule!

Spread the word

A good practice I can recommend is to create a special Properties class tasked with initializing your labels (and another for your preferences, etc.), then inject it in all the client classes you need. Now, all classes have access to your internationalized labels. Truly terrific!

Forget Java WebStart

Weld JAR analyze process is incompatible with Java WebStart. You will likely have such nice error messages:

122 [javawsApplicationMain] WARN org.jboss.weld.environment.se.discovery.URLScanner - could not read entries
java.io.FileNotFoundException: http:\xxxxxxxxxx\weld-logger-1.0.0-CR2.jar (La syntaxe du nom de fichier, de répertoire ou de volume est incorrecte)
  at java.util.zip.ZipFile.open(Native Method)
  at java.util.zip.ZipFile.<init>(Unknown Source)
  at java.util.zip.ZipFile.<init>(Unknown Source)
  at org.jboss.weld.environment.se.discovery.URLScanner.handleArchiveByFile(URLScanner.java:142)
  at org.jboss.weld.environment.se.discovery.URLScanner.handle(URLScanner.java:126)
  at org.jboss.weld.environment.se.discovery.URLScanner.scanResources(URLScanner.java:107)
  at org.jboss.weld.environment.se.discovery.SEWeldDiscovery.scan(SEWeldDiscovery.java:71)
  at org.jboss.weld.environment.se.discovery.SEWeldDiscovery.<init>(SEWeldDiscovery.java:45)
  at org.jboss.weld.environment.se.discovery.SEBeanDeploymentArchive$1.<init>(SEBeanDeploymentArchive.java:45)
  at org.jboss.weld.environment.se.discovery.SEBeanDeploymentArchive.<init>(SEBeanDeploymentArchive.java:44)
  at org.jboss.weld.environment.se.discovery.SEWeldDeployment.<init>(SEWeldDeployment.java:37)
  ...
  at com.sun.javaws.Launcher.run(Unknown Source)
  at java.lang.Thread.run(Unknown Source)

I hope it will be fixed in future releases…

Singletons are NOT evil

Twice already I stumbled upon a strange behaviour: toggle buttons selected when they shouldn’t or state was lost. After debugging like mad, I saw that @PostConstruct methods where called well beyond the initial call. It seems my code called for another injection after that. In order to remedy to this, annotate your class with @Singleton in order to share the instance across multiple calls. I haven’t investigated more than that because:

  • I resolved the bug
  • I don’t know why I shouldn’t use singletons in a Swing application

Conclusion

I’m still in development, so I don’t think I’ve seen all there’s to see. Yet, the previous points can make a good starting point for any project wanting to use CDI in a Java SE context.

And please pardon the puns, I was feeling jolly because of this fine summer of ours :-S

Categories: Java Tags: ,

CDI, an overview – Part 2

May 31st, 2010 Nicolas Frankel 3 comments

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

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.

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
Categories: JEE Tags:

CDI, an overview – Part 1

May 22nd, 2010 Nicolas Frankel 1 comment

Introduction

I may be a Spring fanboy but I’m also convinced a technology should embrace standards. Although Spring is now a de facto standard, it is in competition with other products, like Google Guice for example. It makes my work as an architect harder since my craft is to devise the most perennial 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.

Thus, for a Maven application, all that is required is to add the following dependency:

<dependency>
  <groupId>javax.enterprise</groupId>
  <artifactId>cdi-api</artifactId>
  <version>1.0-SP1</version>
  <scope>provided</scope>
</dependency>

The basics

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

public class WeldServlet extends HttpServlet {

  @Inject private HelloService helloService;

  ...
}

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 I call 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 you can’t if you have more than one implementation to choose from.

Activation

In truth, if you just use the @Inject annotation, you probably will be faced by a NullPointerException. For CDI to activate, you’ll need 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.

<?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">
</beans>

Qualifiers

Yet, such condition is not met most of the time since you’ll probably have at least another mock implementation for your unit 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:

@Qualifier
@Retention(RUNTIME)
@Target( { TYPE })
public @interface Mock {}

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 if you use Maven), since your standard classpath and your testing classpath should be different. Moreover, your unit testing should IMHO not use injection. This would slightly change my servlet to be used both in standard context and unit testing context: I will need to be able to inject in the former case and to set manually in the latter. This is not a problem, since CDI also accepts setter injection like in the following snippet:

public class WeldServlet extends HttpServlet {

  private HelloService helloService;

  @Inject
  public void setHelloService(HelloService helloService) {

    this.helloService = helloService;
  }
  ...
}

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 much 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, just tell CDI that which service you need by providing the needed qualifier:

public class WeldServlet extends HttpServlet {

  @Inject @Mail private ReportService reportService;

  ...
}

When you do not define any qualifier, CDI will use one for you 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 goals of readibility and maintainability. CDI will still let you reach them goals with annotation members. Now, the classes are:

public enum ReportType {

  MAIL, SMS, LOG;    // Adding one more type here is easy
}

@Qualifier
@Retention(RUNTIME)
@Target( { TYPE, FIELD })
public @interface Report {
    ReportType value();
}

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

public class WeldServlet extends HttpServlet {

  @Inject @Report(MAIL)
  private ReportService reportService;
  ...
}

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:

@Singleton
public class HelloServiceImpl implements HelloService {
  ...
}

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 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:

@SessionScoped
public class UserSettings implements Serializable {

  private static final long serialVersionUID = 1L;
  ...
}

At this point, you should probably able to adress 80% of your needs. The next article will tackle advanced subjects like producers and alternatives.

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
Categories: JEE Tags: