JavaEE CDI in one page 5

- Gaurav
Don't be shellfish...Google+FacebookTwitterLinkedInRedditDiggtumblrPinterest

I’ve been reading and checking out the (javaee cdi) CDI- Context and Dependency Injection in JavaEE lately. The more I read, more I fall in love with it. I’ll try and make the article short and less painful for you. And will quickly brush over the important concepts covered in the CDI.

Important Basic Features one should know about

1. The Expression Language Names
As the above link states that the expression language is a mechanism for communication between the presentation layer(web pages) and the application logic(managed beans). While, EL names are nothing but a built in qualifier and then this qualifier can be used to access the bean. Here an example,

@Named("TotalHits")
public class HitCounter implements Counter {
    ...
}

public class HitAccounting {
    @Inject @Named("HitCounter")
    private Counter counter;
}

The class name of the beam is the default EL name, in case the EL name is not explicitly provided.


2. Injecting using Qualifiers instead of EL Names

The above example shows an example using the EL Names. That could be done using a qualifier. Qualifier is nothing but an annotation created to mark a particular bean, here it could be one of the implementations of an interface. It is simply used as follows.

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE})
@java.lang.annotation.Documented
public @interface Informal {}

public interface Greeting {
    public String greet(String name);
}

@Informal
public class InformalGreeting implements Greeting {
    public String greet(String name) {
        return "Hi, " + name;
    }
}

So, the InformalGreeting bean can be injected like this,

@Inject
@Informal
private Greeting greeting;

3. Producer Methods

Producer method introduce the flexibility to select dependencies at runtime. A simple example of the

@Produces
@Coder
@RequestScoped
public Coder getCoder(@New TestCoderImpl tci,
        @New CoderImpl ci) {
    switch (coderType) {
        case TEST:
            return tci;
        case SHIFT:
            return ci;
        default:
            return null;
    }
}

This is just a very simple example of produces annotation. Now, this can be injected as,

@Inject
@Coder
private Coder coder;

Instead of Coder coder, we can use Instance<Coder> in case the producer had some complex computations and could return a variety of implementations.

There is a lot I want to say about producer methods. But since, this article is just  go through, you may find the details at http://www.byteslounge.com/tutorials/java-ee-cdi-producer-methods-tutorial.


4. Using Scopes

The beans can be bound to scope. The default scope is the dependent scope mentioned in the table below. Once the scope for a bean is set, the scope can only be narrowed, it cannot be widened. e.g. if the scope of a bean is set to request, then it cannot be changed to session or application scope. Or even conversation scope.

Scope Annotation Duration
Request @RequestScoped A user’s interaction with a web application in a single HTTP request.
Session @SessionScoped A user’s interaction with a web application across multiple HTTP requests.
Application @ApplicationScoped Shared state across all users’ interactions with a web application.
Dependent @Dependent The default scope if none is specified; it means that an object exists to serve exactly one client (bean) and has the same lifecycle as that client (bean).
Conversation @ConversationScoped A user’s interaction with a JavaServer Faces application, within explicit developer-controlled boundaries that extend the scope across multiple invocations of the JavaServer Faces lifecycle. All long-running conversations are scoped to a particular HTTP servlet session and may not cross session boundaries.

5. Post Construct and PreDestroy Annotation

As the name suggests post-construct and pre-destroy methods are just callback methods. Post construct is called just before the class is put into service in its life cycle. And similarly pre-destroy method is called just before the destruction of the bean.

@PostConstruct
public void createResources() {
....
}

@PreDestroy
public void releaseResources() {
....
}

6. Using Alternatives
It is possible to change the injections by simple changing the code at each @Inject statement, or changing the producer methods. In case, there is a scenario which demands the usage of an alternative, then one has to simply add the class as an alternative in the beans.xml.
In the above examples we saw, that the

<?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>com.kodelog.cdi.qualifiers.InformalGreeting</class>
    </alternatives>
</beans>

And one has to declare the implementation class as an alternative. And every time the alternative is mentioned in the beans.xml, the alternative implementation class will be injected.

@Alternative
public class FormalGreeting implements Greeting { ... }

7. Using Specialization

Usually @Specializes is used along with @Alternative. This is to ensure to that always a particular alternative concrete class is injected at runtime.

@Specializes
public class ServiceImplMock implements Service { ... }

This would ensure that whenever a Service class is injected, the concrete implementation served will always be ServiceImplMock.


8. Disposer Method

A disposes annotation is just the opposite of the produces annotation. The disposes annotation ensures the removal/deletion of the bean created. When the context closes, the related beans are disposed automatically, but dispose can be used to dispose beans automatically.

@PersistenceContext
private EntityManager em;

@Produces
@UserDatabase
public EntityManager create() {
return em;
}

public void close(@Disposes @UserDatabase EntityManager em) {
em.close();
}

9. Events and Observers

The observer pattern can be easily implemented with the flexibility of callbacks being fired BEFORE_COMPLETION, AFTER_COMPLETION, AFTER_SUCCESS and AFTER_FAILURE of the associated transaction. An event has to be declared and then the event handler has to be specified to successfully weave the events and observers.

// A custom annotation for our event

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER})
public @interface InformalGreetEvent {}

// Declaring an event container

@Inject
@InformalGreetEvent
Event<GreetEvent> formalGreetEvent;

// Creating a handler for the events

public void greetEventHandler(@Observes @InformalGreetEvent GreetEvent event) {
    System.out.println(event.getGreetingType());
}

// Code to fire and event and calling the event handler

GreetEvent greet = new GreetEvent();
greet.setGreetingType("Informal");
formalGreetEvent.fire(greet);

10. Interceptors
Interceptors or the cross cutting tasks. The interceptors are invoked before and after invoking the target class/method. Jumping to the example. First we need to declare a interceptor binding.

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

Once we have an interceptor binding, lets go ahead annotate the methods and classes that need to be intercepted.

@Logged
public String pay() {...}

Wait, where the interceptor itself? Here it is.

@Interceptor @Logged
public class LogInterceptor {
    private static Logger LOG = Logger.getLogger(LogInterceptor.class.toString());

    @AroundInvoke
    public Object logMethodEntry(InvocationContext invocationContext) throws Exception {
        LOG.info("Entering method: " + invocationContext.getMethod().getName() + " in class "
                + invocationContext.getMethod().getDeclaringClass().getName());
        return invocationContext.proceed();
    }
}

Also, just like alternatives, the interceptors have to be mentioned in the beans.xml class.

<?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>com.kodelog.cdi.qualifiers.LogInterceptor</class>
     </interceptors>
</beans>

11. Decorators

Yes you are absolutely right. This is just another implementation of the decorator pattern made easy. The decorator elements have to mentioned in the beans.xml as

<?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">
<decorators>
    <class>decorators.CoderDecorator</class>
</decorators>
</beans>

Considering we have an interface called Coder and its implementation CoderImpl, we wish to decorate the existing implementation of Coder. In that case, we would simply inject a decorator of CoderImpl whenever using Coder. And in the coder, internally we’ll use the CoderImpl, i.e. the target implementation which is to be decorated.

public interface Coder {
    public String codeString(String s, int tval);
}

public class CoderImpl {
    @Override
    public String codeString(String s, int tval) {
        // does something
    }
}

// A decorator over the CoderImpl
@Decorator
public abstract class CoderDecorator implements Coder {
    @Inject
    @Delegate
    @Any
    Coder coder;

    @Override
    public String codeString(String s, int tval) {
        int len = s.length();
        return "\"" + s + "\" becomes " + "\"" + coder.codeString(s, tval)
                + "\", " + len + " characters in length";
    }
}

The @Delegate annotation here denotes that the Coder implementation is to be decorated here. And the @Decorator annotation is of course for declaring this implementation as a decorator.

Conclusion

If given a chance, I’ll always try and use CDI instead of using Spring or Google Guice in my projects. Here are two very contradictory articles about Spring vs CDI. Decide for yourself, if CDI can replace Spring in your application.

  1. http://java.dzone.com/articles/why-java-ee-lost-and-spring
  2. http://www.javacodegeeks.com/2011/11/from-spring-to-java-ee-6.html

The article one brings into picture the new data accessing technologies and Spring Data. That seems to be a plus one for Spring. But as far as applications with JPA are concerned, CDI is as powerful and flexible as Spring.

 

Now, that you feel like knowing more about CDI, catch the detailed action @http://docs.oracle.com/javaee/6/tutorial/doc/gjbnr.html

Don't be shellfish...Google+FacebookTwitterLinkedInRedditDiggtumblrPinterest
  • http://publi-hispanovideo.com/read_blog/227551/effortless-programs-of-how-to-get-a-girlfriend-explained Stacey

    Appreciate this post. Let me try it out.

  • http://www.skillipedia.com Faisal

    Clear and useful intro into DI.
    You are welcome to feature your articles
    at skillipedia.com – a professional hub for coders

  • Fernando

    What I love about google guice is the ability to define the Injector problematically. This give us the full control of the app during runtime. For example, to turn on/off a feature toggle.

    Using CDI you must replace your beans.xml file. So you need to restart your entire app. Not very interesting approach. :-(

    Hope in the future people from JSR look to what already exists and works before defining lots of xmls around.

    • http://www.kodelog.com gaurav

      I completely agree with you Fernando, I myself am a Guice fan.
      May be in future they’ll completely get rid of the beans.xml.

  • Pingback: Google