Before Java EE 7, EJBs were the only component that supported declarative transactions. This made your CDI beans a popular option when used as a glue between the JSF side and the EJB side, which was in charge to complete the transactions declaratively. So, in other words you could choose to either bloat your CDI Beans with Transactional bolierplate code, or add a component (the EJB) which should be in charge to complete the transactions. 

One of the most interesting news of Java EE 7 is the addition of a transactional (@Transactional) interceptor which can be used to control transaction boundaries in a declarative way by CDI beans, but now only! Even JAX-RS or a Simple Servlet can now run declarative transactions like the EJB counterpart.
So, let's start from Java EE 6. This is an example SessionBean that I used in my training labs to show how to persist data in a Java EE applications:

@Stateless
public class  ServiceBean   {

 

    @Inject
    private Event<SimpleProperty> propEventSrc;

    @Inject
    private EntityManager em;

    public void put(SimpleProperty p){
        try {

            em.persist(p);
            propEventSrc.fire(p);

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }  

    }

    public void delete(SimpleProperty p){

        Query query = em.createQuery("delete FROM SimpleProperty p where p.key='"+p.getKey()+"'");
        query.executeUpdate();
        propEventSrc.fire(p);

    }

}

As you can see, this is a simple EJB that is responsible to finalize the transaction of a CDI application. You might still turn it to a CDI bean, however, you would need to bloat the complexity of your code, as for every EntityManager interaction you would need to perform the following boilerplate checklist:

  • Start your transaction with: tx.begin
  • EntityManager interaction
  • tx.commit
  • Handle errors and eventually issue tx.rollback

so in our case:

public void put(SimpleProperty p){
        try {
            em.getTransaction().begin();
            em.persist(p);
            propEventSrc.fire(p);
            em.getTransaction().commit();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            throw e;
        }  

One of the benefits of Java EE 7 is that now you can apply the ease-of-use facilities of EJB also for other components like CDI. For example you can rewrite the above EJB to run exactly the same as CDI with the javax.transaction.Transactional annotation:
@Model
@Transactional
public class  ServiceBean   {
.....
}

The annotation can be applied also at method level, so that you define transaction boundaries just for one particular method:
@Transactional
public void put(SimpleProperty p){
        try {
            em.getTransaction().begin();
            em.persist(p);
            propEventSrc.fire(p);
            em.getTransaction().commit();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            throw e;
        } 
        
Additionally, you can specify the policy to be used for transactional context to be used (default is SUPPORTS):
@Transactional(Transactional.TxType.REQUIRES_NEW)
public void put(SimpleProperty p){
}

In the above example, if the method is called outside a transaction context, the interceptor must begin a new JTA transaction, the managed bean method execution must then continue inside this transaction context, and the transaction must be completed by the interceptor. But Transactional context is not an exclusive feature of CDI, you can apply it also to other components like REST Web services for example or a simple Servlet.
@WebServlet(name="txservlet", 
urlPatterns={"/txservlet"} )


public class TxServlet extends HttpServlet {
    
    @Inject
    private EntityManager em; 
    
    @Transactional
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        SimpleProperty p = new SimpleProperty();
        p.setKey("mykey");
        p.setValue("myvalue");
        
        try {
             em.persist(p);
        } catch (Exception e) {
            
            e.printStackTrace();
        }  
    }
    
In terms of compilation, you would need to use the jboss-transaction-api_1.2_spec artifact which is still not included in the jboss-javaee-7.0-1.0.0.Final POM (I could find just the 1.1 at the time of writing) so I had to manually specify the version of the dependency as follows:
<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>as7training.lab3</groupId>
    <artifactId>cdi-demo-wildfly</artifactId>
    <packaging>war</packaging>
    <version>1.0.0.Beta2</version>
    <name>CDI demo Maven Webapp</name>
    <url>http://maven.apache.org</url>

    <properties>

        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>


        <!-- maven-compiler-plugin -->
        <maven.compiler.target>1.7</maven.compiler.target>
        <maven.compiler.source>1.7</maven.compiler.source>
    </properties>

    <repositories>
        <repository>
            <id>JBoss Repository</id>
            <url>https://repository.jboss.org/nexus/content/groups/public/</url>
        </repository>
    </repositories>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.jboss.spec</groupId>
                <artifactId>jboss-javaee-7.0</artifactId>
                <version>1.0.0.Final-SNAPSHOT</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

        </dependencies>
    </dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.jboss.spec.javax.transaction</groupId>
            <artifactId>jboss-transaction-api_1.2_spec</artifactId>
            <version>1.0.0.Final</version>
        </dependency>

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

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


        <!-- Import the CDI API -->
        <dependency>
            <groupId>javax.enterprise</groupId>
            <artifactId>cdi-api</artifactId>
            <scope>provided</scope>
        </dependency>
        <!-- Import the Common Annotations API (JSR-250) -->
        <dependency>
            <groupId>org.jboss.spec.javax.annotation</groupId>
            <artifactId>jboss-annotations-api_1.2_spec</artifactId>
            <scope>provided</scope>
        </dependency>
        <!-- Import the Servlet API -->
        <dependency>
            <groupId>org.jboss.spec.javax.servlet</groupId>
            <artifactId>jboss-servlet-api_3.1_spec</artifactId>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>

        <finalName>${project.artifactId}</finalName>

        <plugins>

            <plugin>
                <groupId>org.wildfly.plugins</groupId>
                <artifactId>wildfly-maven-plugin</artifactId>
                <version>1.0.0.Beta1</version>
            </plugin>
        </plugins>
    </build>

</project>

So in conclusion, once EJB are not anymore the only component that can manage declarative txs, you might think this is the end of EJB reign in the Java EE land. My opinion is that EJB still have some unique features like Timers, Async typed invocations and especially a robust remote invocations API, however....this might sensibly change the way you are writing your Java EE applications.   

0
0
0
s2smodern