7 One to Rule them All – CDI

In this chapter, we get in touch with the most current bean technology in Java EE, namely Contexts and Dependency Injection (CDI). Before we start, please verify again that your project is accessible in Codenvy and is up to date, i.e. you finished the previous chapters successfully as described. If this is not the case you can follow the preceding factory link that generates a project environment for you[1].

Project after Chapter 6 (EJB)

Project after Chapter 6 (EJB)


CDI is the newest Java component technology. CDI 1.1 is part of Java EE 7. CDI is a very modern managed bean technology providing an enhanced dependency mechanism together with several scopes for JSF applications. Furthermore, CDI supports loose coupling by event-based messaging within the same Java virtual machine. That means, CDI beans can fire events which other CDI beans may catch and process. CDI provides similar features as EJB. E.g. since CDI 1.1 it is possible to configure the same transactional behaviour as for EJB beans. Additionally, CDI provides a mechanism to extend its abilities. Several project use this mechanism to provide CDI extensions, e.g. Apache DeltaSpike or Seam 3. In the following, we will show how to replace JSF Managed Beans as well EJB in our sample application My-Memo by CDI.

7.1 Using CDI for Controllers

The “C” in CDI stands for “Contexts”. Beans are always injected into a certain context or scope that determines their lifetime. Like JSF Managed Beans, CDI provides several scopes for JSF applications in the kind of Java annotations. If not configured in another way using the file beans.xml, any bean class that is annotated with a CDI Scope is managed during runtime by the CDI container. Besides the basic scopes that have already been provided by JSF Managed Beans (@ApplicationScoped, @SessionScoped, @ViewScope and @RequestScoped), CDI 1.1  (package javax.enterprise.context) and JSF 2.2 (package javax.faces.flow) provide further scopes in Java EE 7 as depicted in Tab 7-1.

Scope Description
@Dependent  The bean inherits the scope of the bean that injected it.
@ConversationScoped  The bean lives as long as a conversation is active. A conversation is explicitly started and stopped in the code. The bean may survive several views.
@FlowScoped  These beans are backing beans for JSF Faces Flows.

CDI beans that need to be accessed by JSF Facelets directly must be annotated with @Named (package javax.inject). If no specific name is defined by the annotation, the name that can be used in the EL expression of the Facelet matches the bean’s class name beginning with a lower case letter.

Hence, all we have to do to turn our controller bean MemoController from a JSF Managed Bean into a CDI bean is to exchange the scope annotation and to add @Named at the class level (see Listing 7-1).

package press.turngeek.mymemo.controller;

import java.io.Serializable;
import java.util.List;

import javax.enterprise.context.SessionScoped;
import javax.ejb.EJB;
import javax.inject.Named;

import javax.faces.event.ActionEvent;

import press.turngeek.mymemo.model.Memo;
import press.turngeek.mymemo.service.MemoServiceBean;

@SessionScoped
@Named
public class MemoController implements Serializable {

    private static final long serialVersionUID = 8994022512914167890L;

    private Memo memo;

    @EJB
    private MemoServiceBean memoService;

    public MemoController() {
        memo = new Memo();
    }

    public Memo getMemo() {
        return memo;
    }

    public void setMemo(Memo memo) {
        this.memo = memo;
    }

    public void doAdd(ActionEvent event) {
        memoService.addMemo(memo);
        memo.setDescription("");
    }

    public void doReset(ActionEvent event) {
        memoService.resetMemos();
    }

    public List<Memo> getMemos() {
        return memoService.getAllMemos();
    }
}

Listing 7-1 MemoController class (CDI)

The Faclet memos.xhtml can be leaved unchanged, because the name of the bean remains the same (memoController). Please verify your code and run the application again to check the expected behaviour.

7.2 Using CDI for BusinessLogic and Data Storage

Now we address our bean classes MemoStorage and MemoServiceBean that were  implemented as EJBs in the last section. At a first glance, it seems to be desirable to set their scopes to session scope, since we want to store our memos in the session again.

Let us start with our class MemoStore. Using session scope again, means that the application server must be able to serialize beans so that we have to implement java.io.Serializable again.

package press.turngeek.mymemo.data;

import java.io.Serializable;
import java.util.List;
import java.util.LinkedList;

import javax.enterprise.context.SessionScoped;

import press.turngeek.mymemo.model.Memo;

@SessionScoped
public class MemoStore implements Serializable {

    private static final long serialVersionUID = -3258831452772896931L;

    private List<Memo> memos;

    public MemoStore() {
        memos = new LinkedList<Memo>();
    }

    public List<Memo> findAll() {
        return memos;
    }


    public void persist(Memo memo) {
        memos.add(memo);
    }

    public void removeAll() {
        memos.clear();
    }
}

Listing 7-2 MemoStore class (CDI)

As already mentioned, CDI provides the same possibilities as EJB to add transactional behaviour to beans. Currently, the EJB container executes each method of our SSB in a new transaction. In order to receive the same behaviour for a CDI bean, the activation can be declared with the annotation @Transactional (package javax.transaction) at the class level. Setting the only attribute value of the annotation to the transaction type Transactional.TxType.REQUIRED leads to the desired behaviour.

CDI beans can be easily related to another by an advanced DI mechanism. Besides field injection that we already know from JSF Managed Beans and EJB, it adds e.g. constructor and method injection (i.e. at runtime arguments of constructors or methods are injected by the CDI container) too. Further, the mechanism adds a fine grained resolution of demanded types at the injection point by a new qualifier concept. But at this point, we don’t have to go into detail, because we just need a simple field injection. This can be realized using the annotation @Inject (package javax.inject.Inject). Now, we can refactor our class MemoServiceBean as depicted in Listing 7-3.

package press.turngeek.mymemo.service;

import java.util.Date;
import java.util.List;

import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.transaction.Transactional;

import press.turngeek.mymemo.model.Memo;
import press.turngeek.mymemo.data.MemoStore;

@RequestScoped
@Transactional(value=Transactional.TxType.REQUIRED)
public class MemoServiceBean {

    @Inject
    private MemoStore memoStore;

    public List<Memo> getAllMemos() {
        List<Memo> memos = memoStore.findAll();
        return memos;
    }

    public void addMemo(Memo memo) {
        Memo newMemo = new Memo();
        newMemo.setDescription(memo.getDescription());
        newMemo.setCreated(new Date());
        memoStore.persist(newMemo);
    }

    public void resetMemos() {
        memoStore.removeAll();
    }
}

Listing 7-3 MemoServiceBean class (CDI)

As you can see, we didn’t use session scope for our service. Instead, we use request scope. The reason for this is that we don’t store any session data in the bean. For each request a new service bean is created and provided with a reference to the session scoped MemoStore bean by the DI mechanism of CDI (@Inject). This relieves the server and avoids wasting resources.

Finally, we have to update our controller bean MemoController too. Currently, we still use the EJB DI mechanism (@EJB). This won’ work anymore, since MemoServiceBean is no longer managed by the EJB container, but by the CDI container. Consequently, we have to exchange @EJB by @Inject.  We also have to make our mind up about which CDI scope to use. The only data stored in the controller bean is an instance of the class Memo. Since this data is only needed as long the user works with our only view, view scope is preferrable over session scope[2]. The resulting code is presented in Listing 7-4.

package press.turngeek.mymemo.controller;

import java.io.Serializable;
import java.util.List;

import javax.faces.view.ViewScoped;
import javax.inject.Inject;
import javax.inject.Named;

import javax.faces.event.ActionEvent;

import press.turngeek.mymemo.model.Memo;
import press.turngeek.mymemo.service.MemoServiceBean;

@ViewScoped
@Named
public class MemoController implements Serializable {

    private static final long serialVersionUID = 8994022512914167890L;

    private Memo memo;

    @Inject
    private MemoServiceBean memoService;

    public MemoController() {
        memo = new Memo();
    }

    public Memo getMemo() {
        return memo;
    }

    public void setMemo(Memo memo) {
        this.memo = memo;
    }

    public void doAdd(ActionEvent event) {
        memoService.addMemo(memo);
        memo.setDescription("");
    }

    public void doReset(ActionEvent event) {
        memoService.resetMemos();
    }

    public List<Memo> getMemos() {
        return memoService.getAllMemos();
    }
}

Listing 7-4 MemoController class (CDI)

7.3 Conclusions

In this section, we introduced CDI as a new component technology that comprises functionalities of JSF Managed Beans and EJB. In our application, we replaced both technologies by CDI and that simplified the resulting project. From our point of view there is no need to use JSF Managed Beans in the future anymore. CDI contains all features of JSF Managed Beans and provides more functionalities and a state of the art DI mechanism. JSF Managed Beans are deprecated to our opinion.

Although, we were able to replace EJB by CDI in our application, this is not always possible in general. Indeed, the CDI standard provides some features that are provided by EJB in the same way (e.g. transactional behaviour), but the EJB standard still has some features that are not supported by CDI out-of-the box (e.g. security or timers). On the other hand, more and more features are added to CDI by extensions, so that in the near future EJB might be replaced by CDI, too.

In current projects, CDI and EJB are used together successfully. Nevertheless, it is recommendable in these cases not to mix bean technologies within one layer of the software architecture.

If you are not happy with your own implementation, you can compare your implementation with ours by following the factory link below.

Project after Chapter 7 (CDI)

Project after Chapter 7 (CDI)


7.4 Further Reading

Currently, there are only few books that address CDI exclusively. Below, you will find a reference to a book that gives an introduction to the reference implementation Weld. Further, there are several books about Java EE or Java EE technologies like EJB that provide single chapters about CDI. One example is listed below, too.

Ken Finnigan, 2013. JBoss Weld CDI for Java Platform. Edition. Packt Publishing.

Debu Panda, 2014. EJB 3 in Action. Second Edition Edition. Manning Publications. (Chapter 12 is about CDI)

Discussion

Use the message board below to give the authors your feedback or to discuss this page’s topic with other readers (in English please!). Please don’t expect the authors to answer directly, but they might update the content of this site according to your feedback.


  1. Remember, if you sign up to Codenvy, you will be able to persist the project in your workspace. This enables you to store intermediate states of your project and by that to make a break when ever you like. Otherwise, all your changes are volatile and will be lost after closing the browser.
  2. In fact, since we clear the properties of the Memo object stored in the controller after adding a new memo to the list, even request scope would be sufficient for the scope of the controller. Nevertheless, we prefer the view scope, since in general it is necessary to work on the same data as long as the user stays on the same view.