style="display:inline-block;width:728px;height:90px"
data-ad-client="ca-pub-5164839828746352"
data-ad-slot="7563230308">

JSE - Ejemplo básico de inyección de dependencias con CDI, DeltaSpike, Weld; persistencia: Batoo JPA con H2,Transacción incluida

Bueeeeeno... pues resulta que andando de ocioso, quise hacer algo en JSE que incluyera algo de inyección de dependencias. Estuve viendo opciones y me pareció buena idea hacer algo con CDI (de spring hay hartos ejemplos) y las casi recién nacidas extensiones de Apache Delta Spike y para la parte de persistencia, vagando por las internetes me encontré con Batoo que clama ser mucho más rápido que Hibernate (éso es ooooootro tema) y pues decidí incluirlo para mi ejemplo, para la base de datos usé H2; manos a la obra:

De entrada, como acá en el trabajo no puedo usar Maven, tuve que bajar y configurar todo casi a mano, la lista de jars queda así:

-guava-14.0.1.jar
-commons-lang-2.6.jar
-validation-api-1.0.0.GA.jar
-bonecp-0.7.1.RELEASE.jar
-h2-1.3.171.jar
-commons-dbutils-1.5.jar
-commons-io-2.4.jar
-asm-3.3.1.jar
-deltaspike-cdictrl-weld-0.3-incubating.jar
-deltaspike-core-api-0.3-incubating.jar
-deltaspike-core-impl-0.3-incubating.jar
-deltaspike-jpa-module-api-0.3-incubating.jar
-deltaspike-cdictrl-api-0.3-incubating.jar
-deltaspike-jpa-module-impl-0.3-incubating.jar
-weld-api.jar
-weld-spi.jar
-weld-se.jar
-batoo-annotations-2.0.1.0-RTM.jar
-batoo-jdbc-2.0.1.0-RTM.jar
-batoo-jpa-2.0.1.0-RTM.jar
-batoo-jpa-spi-2.0.1.0-RTM.jar
-jpql-0.1.6.jar
-parser-2.0.1.0-RTM.jar
-persistence-api-2.0.jar

Ahora, para la parte de código, el punto de entrada para detonar el contexto de inyección de dependencias, queda así:

import org.apache.deltaspike.cdise.api.CdiContainer;
import org.apache.deltaspike.cdise.api.CdiContainerLoader;
import org.apache.deltaspike.cdise.api.ContextControl;
import org.apache.deltaspike.core.api.provider.BeanProvider;

public class Access {
       
    public static void main(String[] args) {
        //con las dos lineas siguientes se detona el contenedor de inyección de dependencias
        CdiContainer cdiContainer = CdiContainerLoader.getCdiContainer();
        cdiContainer.boot();
        //con las siguientes el alcance(scope) de la aplicación, se puede cambiar ;-)
        ContextControl contextControl = cdiContainer.getContextControl();
        contextControl.startContext(RequestScoped.class);
        //acá la clase con la que vamos a comenzar (que sería algo como un segundo main
        Mediator mediator = BeanProvider.getContextualReference(Mediator.class, false);
        //ejecutamos el metodo que nos da entrada a nuestro programa
        mediator.execInTransaction();
        //detenemos el contexto
        contextControl.stopContext(RequestScoped.class);
        //damos de baja el contenedor
        cdiContainer.shutdown();
    }  
}

Ya con ésto podemos dentro del código de la clase Mediator (que puede ser el punto de entrada a toda una aplicación) obtener recursos mediante anotaciones, el código de dicha clase es:

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

@RequestScoped
public class Mediator{

        @Inject
        private InjectedByDI injectedByDI;
       
        //este es el metodo que se ejecuta en la clase anterior
        public void execInTransaction() {
                injectedByDI.tryToExec();
        }
}

Como se puede ver, ya tengo una interface InjectedByDI que está anotada con @Inject con lo cual ya no tenemos que hacer la implementación a mano; se ejecuta el método tryToExec(); en la implementación el código queda así:

import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Default;
import javax.inject.Inject;
import javax.persistence.EntityManager;

import org.apache.deltaspike.jpa.api.transaction.Transactional;

@RequestScoped
@Default
public class InjectedByDIImpl implements InjectedByDI {

        @Inject
        EntityManager entityManager;
       
        @Override
        @Transactional
        public void tryToExec() {
                System.out.println(">>> begin tryToExec()");
                AppUser appUser = new AppUser();
                appUser.setId((int)(Math.random()*100));
        this.entityManager.persist(appUser);
        System.out.println(">>> end tryToExec()");
        }
}

En la implementación ya tengo anotado mi entityManager también anotado, y la implementación de mi método tryToExec la cual insertará un registro en mi base de datos (un objeto de la clase AppUser.

Ahora, aquí hay un punto a notar, porqué el EntityManager no está anotado con: @PersistenceContext(unitName="el nombre de la unidad de persistencia"); bueno, según la documentación es porque éso sólo está permitido en ambientes EE; entonces, como no soy nadie para discutir las docs, y en la página de DeltaSpike viene un ejemplo, pues de ahí parto para poder generar mi EntityManager; el código queda así:

import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Default;
import javax.enterprise.inject.Disposes;
import javax.enterprise.inject.Produces;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class EntityManagerProducer {

        private EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("aqui el nombre de la unidad de persistencia");

        @Produces
        @Default
        @RequestScoped
        protected EntityManager createEntityManager() {
                return this.entityManagerFactory.createEntityManager();
        }

        protected void closeEntityManager(@Disposes EntityManager entityManager) {
                if (entityManager.isOpen()) {
                        entityManager.close();
                }
        }
}

Con ésta clase, ya tenemos disponible los EntityManager por medio de la anotación @Inject.

La clase de mi bean, pojo, modelo, VO, DTO, entidad o como le quieran llamar quedó:

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="APP_USER")
public class AppUser implements Serializable {
        private static final long serialVersionUID = 1L;
           
        @Id
        @Column(name="ID" ,nullable=false)
        private Integer Id;
       
        public Integer getId() {
                return this.Id;
        }

        public void setId(Integer Id) {
                this.Id = Id;
        }  
}

Ya con ésto queda el código completo del ejemplo.
Los ficheros de configuración quedan de la siguiente forma:
el beans.xml que es algo así como el applicationContext.xml de spring, queda:

<?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 <a href="http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
" title="http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
">http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
</a>    <interceptors>
                <class>org.apache.deltaspike.jpa.impl.transaction.TransactionalInterceptor</class>
        </interceptors>
</beans>

Sólo contiene la declaración del interceptor de transacciones propio del DeltaSpike, y ya.
Y el persistence.xml queda:

<?xml version="1.0" encoding="UTF-8"?>
<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 <a href="http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
" title="http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
">http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
</a>    <persistence-unit name="aqui el nombre de la unidad de persistencia" transaction-type="RESOURCE_LOCAL">
                <provider>org.batoo.jpa.core.BatooPersistenceProvider</provider>
               
                <class>paquete1.paquete2.AppUser</class>
               
                <properties>
                        <property name="javax.persistence.jdbc.driver" value="org.h2.Driver" />
                        <property name="javax.persistence.jdbc.url" value="jdbc:h2:tcp://localhost/~/test" />
                        <property name="javax.persistence.jdbc.user" value="sa" />
                        <property name="javax.persistence.jdbc.password" value="" />
                </properties>
        </persistence-unit>
</persistence>

Lo único que no me gustó (y que espero corrijan en otro release) es el control de transacciones que no queda taaan a detalle como el de las anotaciones de spring (las propiedades de isolation level y propagation), de ahí en fuera, me gusta cómo va quedando éste rollito de unificar las varias extensiones existentes (CODI,CanDI,Seam, por mencionar algunas) en DeltaSpike.

Espero que en algún desarrollo en Swing tengan oportunidad de incluir y probar algo como mi ejemplo :-)
Digo, es una posibilidad (ya sabemos que existe Griffon, antes de que lo venga a promocionar Enrique =D )
Hasta la próxima.

style="display:inline-block;width:728px;height:90px"
data-ad-client="ca-pub-5164839828746352"
data-ad-slot="7563230308">