CDI Power Constructs for JEE-6: @Inject, @Qualifier, @Produces, @Disposes and @Named
In pre-JEE 5 era, tiered architectures boasted of having loosely coupled layers and a predefined flows for the request-response were outlined, designed, implemented and tested. Core JEE patterns evolved which defined breadths of request processing and response throwbacks, for variety of scenarios.
A thick layered architecture would have a view controlled by controller command, which invoked a facade and chain of command passed on to DAO or EntityBean which manipulated the model. Various configuration idiosyncrasies had to be carefully set and presented in the final deployment.
Enter JEE 6 – the era of configuration free, and annotation driven wiring of components. The JSR-299 (Contexts and Dependency Injection for Java) improvises over JSR-330 (Dependency Injection for Java) and brings the power of Inversion of Controller to enterprise container. Five annotation constructs : @Inject, @Qualifier, @Produces, @Disposes and @Named provide the basic building blocks for getting a thin loosely coupled layered modular structure to the view, hiding the boilerplate code one had to write before JEE 6. Lets briefly look at these annotations and how do they fit in with regard to a shopping cart example:
@Qualifier
We use @Qualifier for defining different bean types. In JEE 6 context, @Qualifier is used to define independent functional flows. In case of shopping cart example, it could denote the shopping cart access manager as shown below:
@Qualifier
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface ShoppingCart {}
@Produces
The annotation @Produces is used to instantiate a bean type, specifically on an . If a bean type is a qualified (i.e.) annotated with @Qualifier, the @Produces with be followed by the custom qualifier interface. In the shopping cart example above, if we need to define a factory method to return a manager instance to be available under a managed bean, we could defines as below:
public @Produces @ShoppingCart ShoppingCartManager getShoppingCart() {
return new ShoppingCartManagerImpl();
}
where ShoppingCartManager defines methods to query and add items to the cart as below:
public abstract class ShoppingCartManager{
@PersistenceContext EntityManager em;
public abstract List<Items> getAllItems();
public abstract void addItem(Item item);
...
}
@Disposes
A @Dispose annotation is used in exact opposite semantics of @Produces. If you want release some held resources by the manager, or destroy the session specific shopping cart in this example, you could use it on the method.
public void clearShoppingItem(@Disposes @ShoppingCart ShoppingCartManager cart) {
cart.clearItems();
cart = null;
}
@Inject
@Inject provides the ability to define the dependency injection at the point of usage, qualified or unqualified. If a bean type has been qualified, the appropriate Qualifier is as well used.
@Inject @ShoppingCart ShoppingCartManager manager;
@Named
@Named annotation helps the component to be used in the presentation or view layer using EL, supported by Camelcase variable naming convention. So in the shopping cart example, using #{items} would query the accessor method to retreive the shopping cart items
@Inject @ShoppingCart ShoppingCartManager manager;
@Named
public List<Item> getItems() {
return manager.getAllItems();
}
Using these constructs, one can implement complex workflows, without configuration hassles, and maintaining high cohesion and loose coupling.