Java EE 6 CDI example application

In this tutorial we will show how to upgrade our Java EE 6 EJB based application into a CDI based application using Eclipse and Eclipse Maven plugin.

Contexts and Dependency Injection(CDI) is a new addition to the Java EE specification as of Java EE 6. It provides several benefits that were missing to Java EE developers, such as allowing any JavaBean to be used as a JSF managed bean, including stateless and stateful session beans.

CDI elementary unit is still the Bean. Compared with EJBs, CDI features a different, more flexible kind of Bean: one of the most important differences between the two approaches is that CDI Beans are contextual that s they live in a well defined scope.

In this tutorial we will create a CDI based application using Eclipse and Maven Eclipse plugin.

Start by creating a new Maven Project from the File Menu:

java ee 6 tutorial CDI maven eclipse plugin

Now move to the Archetype selection screen and enter the maven-archetype-webapp which will produce a standard Java EE Web application project which is suited as well for applications containing EJBs and CDI beans:

java ee 6 tutorial CDI maven eclipse plugin

Next choose as Artifact Id “javaee6example” which will be our Project name and enter a Package & Group Id for your project:

newproject3

Ok. Now you should have in your project explorer a basic skeleton of Java EE project:

javaee6example
¦   pom.xml
¦
+---src
¦   +---main
¦       +---java
¦       ¦
¦       +---resources
¦       ¦
¦       +---webapp
¦           ¦
¦           +---WEB-INF
¦                   faces-config.xml
¦                   web.xml
¦
+---target

The first thing to settle is Maven pom.xml which will contain the required dependencies and the plugins which are necessary to deploy the application on JBoss AS 7.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.mastertheboss</groupId>
    <artifactId>javaee6example</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>Java EE 6 webapp project</name>
    <description>A starter Java EE 6 webapp project for use on JBoss AS 7, generated from the jboss-javaee6-webapp archetype</description>

    <properties>

        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <jboss.home>C:\jboss-as-7.1.1.Final</jboss.home>
        <maven.build.timestamp.format>yyyyMMdd'T'HHmmss</maven.build.timestamp.format>

    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.jboss.spec</groupId>
                <artifactId>jboss-javaee-web-6.0</artifactId>
                <version>2.0.0.Final</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>

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

        <dependency>
            <groupId>org.jboss.spec.javax.annotation</groupId>
            <artifactId>jboss-annotations-api_1.1_spec</artifactId>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.jboss.spec.javax.ws.rs</groupId>
            <artifactId>jboss-jaxrs-api_1.1_spec</artifactId>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.hibernate.javax.persistence</groupId>
            <artifactId>hibernate-jpa-2.0-api</artifactId>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.jboss.spec.javax.ejb</groupId>
            <artifactId>jboss-ejb-api_3.1_spec</artifactId>
            <scope>provided</scope>
        </dependency>

    </dependencies>

    <build>

        <finalName>${project.artifactId}</finalName>
        <plugins>
            <!-- Compiler plugin enforces Java 1.6 compatibility and activates annotation 
                processors -->
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.1</version>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.1.1</version>
                <configuration>
                    <!-- Java EE 6 doesn't require web.xml, Maven needs to catch up! -->
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.jboss.as.plugins</groupId>
                <artifactId>jboss-as-maven-plugin</artifactId>
                <version>7.1.1.Final</version>
            </plugin>
        </plugins>
    </build>

    <profiles>
        <profile>
            <!-- The default profile skips all tests, though you can tune it to run 
                just unit tests based on a custom pattern -->
            <!-- Seperate profiles are provided for running all tests, including Arquillian 
                tests that execute in the specified container -->
            <id>default</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <build>
                <plugins>
                    <plugin>
                        <artifactId>maven-surefire-plugin</artifactId>
                        <version>2.4.3</version>
                        <configuration>
                            <skip>true</skip>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </profile>
    </profiles>
</project>

Please notice that this pom.xml does not contain dependency versions for the single libraries. The dependency version is resolved using a BOM (Bill of materials) which specifies the exact version for the Java EE stack. See this tutorial for more info about it.


Now we will start adding classes. We will add the following classes:

  • SimpleProperty: an Entity Bean for storing our Properties
  • Manager: a CDI Bean which acts as a glue between the JSF view and the EJBs
  • ServiceBean: a Stateless EJB which will carry on transactional jobs (Inserts, Deletes)
  • GenericProducer: a CDI Producer Bean used to instantiate container resources (The Entity Manager)
  • Producer: a CDI Producer Bean used as a factory of SimpleProperty for the JSF view
  • RepositoryManager: a CDI Bean used to perform queries and populate SimpleProperty objects
    So start by adding the class com.mastertheboss.model.SimpleProperty class:
@Entity
public class SimpleProperty {
 
    @Id 
    @Column(name="id")
    private String key;

    private String value;

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
   
}

Now it’s the turn of the com.mastertheboss.bean.Manager class:

@Model
public class Manager {
  
    @Inject
    ServiceBean ejb;
    
    @Produces
    @Named
    SimpleProperty property;
    
    @Inject
    Producer producer;
    
    @PostConstruct
    public void initNewProperty() {
        property = new SimpleProperty();
    }
     
    public void save() {
        ejb.put(property);
        initNewProperty();
    }

    public void clear(SimpleProperty property) {
        ejb.delete(property);
         
    }
 

}

Key Point

Notice this class contains a SimpleProperty instance with a @Produces @Named annotation. This means that this field will be used as a factory for an instance of the SimpleProperty, which will be eventually exposed (via @Named annotation) to the JSF EL. The benefit of using this approach is that you won’t need creating boilerplate code for the single fields of SimpleProperty that need

Here’s the turn of the com.mastertheboss.ejb.ServiceBean EJB which will perform some transactional activities such as storing new SimpleProperty and deleting them as well from the DB:

@Stateless
public class  ServiceBean   {

    @Inject
    private Event<SimpleProperty> propEventSrc;
    
    @Inject
    private EntityManager em;
    
    public void put(SimpleProperty p){
         
          em.persist(p);
          propEventSrc.fire(p);
    }
     
    public void delete(SimpleProperty p){

        Query query = em.createQuery("delete FROM com.sample.model.SimpleProperty p where p.key='"+p.getKey()+"'");

        query.executeUpdate();
        propEventSrc.fire(p);
                   
    }

}

In this example we use a com.mastertheboss.producer.GenericProducer class to instantiate some typical container resources such as the EntityManager, which can now be safely injected into your beans via the @Inject annotation:

public class GenericProducer {
    @SuppressWarnings("unused")
    @Produces
    @PersistenceContext
    private EntityManager em;
}

The other Producer class namely com.mastertheboss.producer.Producer will be used to Produce an ArrayList of @Named SimpleProperty which can be therefore be exposed to the JSF EL:

@RequestScoped
public class Producer {
    @Inject RepositoryManager db;

    private List<SimpleProperty> propertyList;

    public void onMemberListChanged(@Observes(notifyObserver = Reception.IF_EXISTS) final SimpleProperty member) {
        retrieveAllSeatsOrderedByName();
    }
    
    @Produces
    @Named
    public List<SimpleProperty> getPropertyList() {
        return propertyList;
    }

    public void setProperty(List<SimpleProperty> property) {
        this.propertyList = propertyList;
    }

    @PostConstruct
    public void retrieveAllSeatsOrderedByName() {

        propertyList = db.queryCache();

    }
    
}

Key Point

Another feature of this Producer class is the Observer pattern. Observers, just like the name suggests, can be used to observe objects. An observer method is notified whenever an object is created, removed, or updated. In our example, it allows refreshing the list of Seats whenever they are needed.
To be precise, in our example, we are using a conditional Observer, which is denoted by the expression notifyObserver = Reception.IF_EXISTS. This means in practice that the observer method is only called if an instance of the component already exists. If not specified, the default option (ALWAYS) will be that the observer method is always called (If an instance doesn’t exist, one will be created).

Finally, the last class we will add is the com.mastertheboss.repository.RepositoryManager class which will use the EntityManager instance to perform a basic query on the SimpleProperty table:

public class RepositoryManager {
 
    @Inject
    private EntityManager em;

    public List<SimpleProperty>  queryCache(){
        Query query = em.createQuery("FROM com.mastertheboss.model.SimpleProperty");

        List <SimpleProperty> list =  query.getResultList();
        return list;          
    }
}

Handling Persistence

In order to be able to use JPA, you need to add a persistence.xml file into the src\main\resources\META-INF folder of your project:

<persistence version="2.0"
   xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="
        http://java.sun.com/xml/ns/persistence
        http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
   <persistence-unit name="primary">

      <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source>
  
      <properties>
         <!-- Properties for Hibernate -->
         <property name="hibernate.hbm2ddl.auto" value="create-drop" />
         <property name="hibernate.show_sql" value="false" />
      </properties>
   </persistence-unit>
</persistence>

In this example we’re using the default H2 datasource which is bound into the JNDI java:jboss/datasources/ExampleDS

Now about the JSF view, we will add an index.xhtml page that will capture the SimpleProperty fields in the upper panel and display them in a data table in the lower panel:

<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:c="http://java.sun.com/jsp/jstl/core">
<h:head>
    <style type="text/css">
<!-- styles not included for brevity -->
</style>
</h:head>
<h:body>
    <h2>JSF 2 example on JBoss 7</h2>
    <h:form id="jsfexample">
        <h:panelGrid columns="2" styleClass="default">

            <h:outputText value="Enter key:" />
            <h:inputText value="#{property.key}" />

            <h:outputText value="Enter value:" />
            <h:inputText value="#{property.value}" />

            <h:commandButton actionListener="#{manager.save}"
                styleClass="buttons" value="Save key/value" />
        
            <h:messages />

        </h:panelGrid>

        <h:dataTable value="#{propertyList}" var="item"
            styleClass="table" headerClass="table-header"
            rowClasses="table-odd-row,table-even-row">
            <h:column>
                <f:facet name="header">Key</f:facet>
                <h:outputText value="#{item.key}" />
            </h:column>
            <h:column>
                <f:facet name="header">Value</f:facet>
                <h:outputText value="#{item.value}" />
            </h:column>
            <h:column>
                <f:facet name="header">Delete</f:facet>
                <h:commandButton actionListener="#{manager.clear(item)}"
                styleClass="buttons" value="Delete" />
            </h:column>

        </h:dataTable>
    </h:form>
</h:body>
</html>

Finally, in order to be able to include this page as welcome page, include the following index.jsp into your project:

<html>
<head>
  <meta http-equiv="Refresh" content="0; URL=index.xhtml">
</head>
</html>

Running the Project from Eclipse

Once you are done with the Project set up your can deploy it from within your Eclipse Environment. Create a new Maven run configuration and add as Base Directory the Project’s base directory ( you can explore through your projects using the Browse_Workspace button). Next enter the Goals “clean package jboss-as:deploy” which will respectively delete build files, compile & package, deploy on a running JBoss AS instance.

java ee 6 tutorial CDI maven eclipse plugin

Please remember to add the jboss.home into the pom.xml file in order to be able to use the JBoss Maven plugin.

Once done click Apply and Run. This will deploy your javaee6example.war to JBoss AS 7 which can be accessed at http://localhost:8080/javaee6example/

java ee 6 tutorial CDI maven eclipse plugin

Download the sources: you can access the source code at my fork of JBoss developer framework

Found the article helpful? if so please follow us on Socials