JavaData & JavaExploring Context Dependency Injection (CDI) 2.0 of Java EE 8

Exploring Context Dependency Injection (CDI) 2.0 of Java EE 8

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

The CDI 2.0 package is a major update delivered with Java EE 8 that reiterates its status as a core technology of the Java EE platform. This emphasizes a significant change in the Java EE development arena. Other collaborative technologies, such as JSF and Java Security, are leveraging CDI. JSF has finally deprecated its managed bean model and dependency injection in its favour. The interceptors and bean validation have become more usable with CDI. This article delves into the CDI 2.0 update and its implication on Java EE enterprise development.

CDI Overview

CDI, aka Context Dependency Injection, is the core dependency injection framework of the Java EE platform. It provides a uniform architecture for dependency injection and the life cycle management of managed beans. Since its inception in 2009 with JEE6, it has come a long way with some major changes. The original idea is a result of Gavin King’s intention to collaborate JSF and EJB so that they can be intertwined to work with in a Web application. This developed a new way of interleaving the Web and transactional tiers of the Java EE platform. The CDI framework of Java EE provides necessary services which enable developers to use enterprise beans along with JSF technology in a convenient manner. Although it was initially targeted towards stateful objects, it later evolved to many broader uses, such as integrating different components in a type safe and loosely coupled manner. Due to its flexible architecture, developers can use enterprise beans along with the Web technology, such as JSF, in a more convenient manner.

Java beans is the source of contextual objects that define the application state and business logic. The JEE container manages the life cycle of these beans by creating and destroying their instances or associating them with the appropriate context. Associating with context essentially refers that they are injected into other objects and execute in the same context. Java beans types are nothing but POJOs with special connotation. According to JSR 365, legal bean types are as follows:

  • It may be an interface, a concrete class, or an abstract class, and may be declared final or have final methods.
  • It may be a parameterized type with actual type parameters and type variables.
  • It may be an array type. Two array types are considered identical only if the element type is identical.
  • It may be a primitive type or raw type. Primitive types are considered to be identical to their corresponding wrapper types in java.lang.

Java EE 8’s CDI 2.0 is a major update that separated the specification into three parts, such as the core specification, Java SE features, and the Java EE features. The central idea of this separation seems to emphasize CDI as a core and fundamental technology that may also be used with Java SE and Java EE references. Although there are many big and small improvement, here we’ll focus on only a couple of them.

CDI Bean Creation Simplified

CDI 2.0 greatly simplifies the use of the producer method. A producer is a type of factory method that acts as a source of objects to be injected, where:

  • The objects to be injected are not required to be instances of beans, or
  • The concrete type of the objects to be injected may vary at runtime, or
  • The objects require some custom initialization that is not performed by the bean constructor.

A producer method is designated by the @Produces annotation. For example, if we want to interleave CDI components with say, a Java EE managed component, we may use the CDI hook as follows:

class JavaEEManagedComponent{
   @PersistentContext
   @Produces
   private EntityManager entityManager;
}

class CDIComponent{
   @Inject
   private EntityManager entityManager;
}

In CDI, this type of factory is represented by the Bean<T> type. The Bean<T> type is not an actual bean but is an interface that defines a type that is used to create producer factory instances. A Bean<T> instance is created implicitly after it finds out the class definition and producer methods. These factory methods also can be added programmatically by user code and register them at run-time. The programmatic adding of Bean<T> is complex and inconvenient with CDI precursor version 1.x because programmers have to decide the default return values for various methods. CDI 2.0 addressed this issue with a builder method which allays many of the problems that its predecessor has. For example, if we write a class without a default constructor, CDI cannot use this class instance as a bean.

public interface Message {
   String getMessageString();
}

public class MessageImpl implments Message {
   private String msg;
   public MessageImpl(String msg) {
      this.msg=msg;
   }
   @Override
   String getMessageString() {
      return msg;
   }
}

But now, with CDI 2.0, we can use implement the Extension interface and use the builder method and enable CDI to recognize it as a bean.

public class MessageExtension implements Extension {

   public void afterBeanDiscovery(@Observes
         AfterBeanDiscovery abd) {
      BeanConfigurator<Object> bc;
      bc = abd.addBean()
      .scope(ApplicationScoped.class)
      .types(Message.class)
      .id("Extension class : "+MessageExtension .class)
      .createWith(new FunctionImpl());
   }

   private static class FunctionImpl implements
         Function<CreationalContext<Object>, Object> {
      public FunctionImpl() {  }
      @Override
      public Object apply(CreationalContext<Object> e) {
         return new MessageImpl("Hello World!");
      }
   }
}

Or, we can use lambda expression to represent the previous snippet for a concise code.

public class MessageExtension implements Extension {

   public void afterBeanDiscovery(@Observes AfterBeanDiscovery
         abd) {
      abd.addBean()
      .scope(ApplicationScoped.class)
      .types(Message.class)
      .id("Extension class : "+MessageExtension .class)
      .createWith(e->MessageImpl("Hello World!");
   }
}

Interceptor Binding to a CDI Bean

With CDI 2.0, it is possible to apply interceptors programmatically to the return value of a producer method. The introduction of the InterceptionFactory interface allows one to create a wrapper instance whose method invocations are intercepted by method interceptors and forwarded to a provided instance. The interface is defined in javax.enterprise.inject.spi package as follows:

public interface InterceptionFactory<T> {
   InterceptionFactory<T> ignoreFinalMethods();
   AnnotatedTypeConfigurator<T> configure();
   T createInterceptedInstance(T instance);
}

The following code snippet gives a glimpse of a producer method using Interceptionfactory.

@Produces
public PersonService produce(InterceptionFactory<PersonService>
      interceptionFactory, BeanManager beanManager) {
   PersonService personBean = null;
   personBean = createRef(beanManager.resolve(
      beanManager.getBeans(PersonService.class)
      .stream()
      .filter(e -> !e.getBeanClass().equals(AppConfig.class))
      .collect(toSet())), beanManager);

   interceptionFactory
      .configure()
      .filterMethods(am -> am.getJavaMember()
      .getName().equals("transactional"))
      .findFirst().ifPresent(m ->
      m.add(new AnnotationLiteral<Transactional>() {
   }));
   return interceptionFactory.createInterceptedInstance
      (personBean);
}

Note:

Interceptors are mainly associated with Java EE managed classes that allow developers to invoke interceptor methods on an associated target class. They are mainly used to implement cross-cutting concerns such as logging, auditing, and security from the business logic. These cross-cutting concerns can be applied to beans via custom annotations and its types may be individually enabled or disabled at deployment time.

Decorators, on the other hand, are similar to interceptors, but apply only to beans of a particular Java interface. Like interceptors, decorators may be enabled or disabled easily at deployment time. Unlike interceptors, decorators are aware of the semantics of the intercepted method.

Accessing beans and working with them programmatically is now more convenient with CDI 2.0. Its predecessors simply lacked this capability. There are many other improvements with the addition of new annotation instances which simplified the way of requesting a bean from the bean manager. This article provides only a couple of the many big and small improvements so far. Refer to the specification for more detail on this and many others.

References

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories