In previous sections we created EJB classes that were not quite POJOs -- in that they defined resource injections that were very specific to EJB. We also burdned the EJB @PostConstruct methods with a lot of setup code that is no longer necessary with JSR-299 Context and Dependency Injection (CDI). We will only touch on a small portion of CDI in this exercise but it will lay the ground work to add more features later as necessary.
$cat javaeeExEJB/src/main/java/myorg/javaeeex/cdi/ResourceConfig.java
package myorg.javaeeex.cdi;
/**
* This class will be used to define a mapping between the dependency
* injection solutions and their source within the container.
*/
public class ResourceConfig {
}import javax.enterprise.inject.Produces;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
public class ResourceConfig {
@Produces
@PersistenceContext(unitName="javaeeEx")
public EntityManager em;
}$cat javaeeEx/javaeeExEJB/src/main/java/myorg/javaeeex/ejb/RegistrarEJB.java
import javax.inject.Inject;
import javax.persistence.EntityManager;
...
@Stateless
public class RegistrarEJB implements RegistrarLocal, RegistrarRemote {
...
@Inject
private EntityManager em;$ mvn clean install -rf :javaeeExEJB -Dit.test=myorg.javaeeex.ejbclient.RegistrarIT#testPing ...
# server.log 22:10:15,404 DEBUG [myorg.javaeeex.ejb.RegistrarEJB] (EJB default - 2) **** init **** 22:10:15,405 DEBUG [myorg.javaeeex.ejb.RegistrarEJB] (EJB default - 2) em=null 22:10:15,428 DEBUG [myorg.javaeeex.ejb.RegistrarEJB] (EJB default - 2) init complete, registrar=myorg.javaeeex.blimpl.RegistrarImpl@2be20e 22:10:15,429 DEBUG [myorg.javaeeex.ejb.RegistrarEJB] (EJB default - 2) ping called
$ touch javaeeExEJB/src/main/resources/META-INF/beans.xml $ tree javaeeExEJB/src/main/resources/META-INF javaeeExEJB/src/main/resources/META-INF |-- beans.xml `-- persistence.xml
$ mvn clean install -rf :javaeeExEJB -Dit.test=myorg.javaeeex.ejbclient.RegistrarIT#testPing ... Tests run: 5, Failures: 0, Errors: 0, Skipped: 0 ... [INFO] ------------------------------------------------------------------------ [INFO] Reactor Summary: [INFO] [INFO] Java EE Exercise EJB .............................. SUCCESS [5.373s] [INFO] Java EE Exercise EAR .............................. SUCCESS [0.744s] [INFO] Java EE Exercise Remote Test ...................... SUCCESS [48.418s] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS
# server.log ... 22:25:38,021 INFO [org.jboss.weld.deployer] (MSC service thread 1-4) JBAS016008: Starting weld service for deployment javaeeExEAR-1.0-SNAPSHOT.ear ... 22:25:55,652 DEBUG [myorg.javaeeex.ejb.RegistrarEJB] (EJB default - 8) **** init **** 22:25:56,418 DEBUG [myorg.javaeeex.ejb.RegistrarEJB] (EJB default - 8) em=org.jboss.as.jpa.container.TransactionScopedEntityManager@1cae20a 22:26:20,423 DEBUG [myorg.javaeeex.ejb.RegistrarEJB] (EJB default - 8) init complete, registrar=myorg.javaeeex.blimpl.RegistrarImpl@1d7dfda 22:26:24,952 DEBUG [myorg.javaeeex.ejb.RegistrarEJB] (EJB default - 8) ping called
In the previous section we needed an EntityManager injected and were successful only because there was a single EntityManager declared. This is not always the case -- so lets create an injection ambiguity by creating a second EntityManager using a @Produces method this time.
//this is a second option for an EntityManager to create an ambiguity
//when selecting on type alone
@Produces
public EntityManager getEntityManager(@JavaeeEx EntityManager em2) {
em2.setProperty("foo", "bar");
return em2;
}
...WeldService: org.jboss.weld.exceptions.DeploymentException: WELD-001409 Ambiguous dependencies for type [EntityManager] with qualifiers [@Default] at injection point [[field] @Inject private myorg.javaeeex.ejb.RegistrarEJB.em]. Possible dependencies [[Resource Producer Field [EntityManager] with qualifiers [@Any @Default] declared as [[field] @Produces @PersistenceContext public myorg.javaeeex.cdi.ResourceConfig.em], Producer Method [EntityManager] with qualifiers [@Any @Default] declared as [[method] @Produces public myorg.javaeeex.cdi.ResourceConfig.getEntityManager()]]]
In the previous section we finished with an ambiguous injection error. In this section we will create a type-safe @Qualifier to complete the injections.
$cat javaeeEx/javaeeExEJB/src/main/java/myorg/javaeeex/cdi/JavaeeEx.java
package myorg.javaeeex.cdi;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* This is a type-safe qualifier that is used to distinguish between
* ambiguous injection choices or place more stringent requirements.
*/
@Qualifier
@Target({ TYPE, METHOD, PARAMETER, FIELD })
@Retention(RUNTIME)
@Documented
public @interface JavaeeEx {
}$cat javaeeEx/javaeeExEJB/src/main/java/myorg/javaeeex/ejb/TestUtilEJB.java
...
import myorg.javaeeex.cdi.JavaeeEx;
@Stateless
public class TestUtilEJB implements TestUtilRemote {
private static Log log = LogFactory.getLog(TestUtilEJB.class);
@Inject @JavaeeEx
private EntityManager em;WELD-001408 Unsatisfied dependencies for type [EntityManager] with qualifiers [@JavaeeEx] at injection point [[field] @JavaeeEx @Inject private myorg.javaeeex.ejb.TestUtilEJB.em]
$ cat javaeeEx/javaeeExEJB/src/main/java/myorg/javaeeex/cdi/ResourceConfig.java
...
@Produces @JavaeeEx
@PersistenceContext(unitName="javaeeEx")
public EntityManager em;
...$ mvn clean install -rf :javaeeExEJB ... Tests run: 5, Failures: 0, Errors: 0, Skipped: 0 ... [INFO] ------------------------------------------------------------------------ [INFO] Reactor Summary: [INFO] [INFO] Java EE Exercise EJB .............................. SUCCESS [5.912s] [INFO] Java EE Exercise EAR .............................. SUCCESS [1.227s] [INFO] Java EE Exercise Remote Test ...................... SUCCESS [11.756s] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS
In the previous section we used a field producer to define the injected bean. This works fine for beans that require no modification. However, if you need to do some bean assembly, you can alternatively use a factory producer.
package myorg.javaeeex.cdi;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Qualifier
@Target({ TYPE, METHOD, PARAMETER, FIELD })
@Retention(RUNTIME)
@Documented
public @interface JavaeeEx2 {
} //this is a second option for an EntityManager to produce a bean that
//requires inputs and manipulation
@Produces @JavaeeEx2
public EntityManager getEntityManager(@JavaeeEx EntityManager em2) {
em2.setProperty("foo", "bar");
return em2;
} @Inject @JavaeeEx2
private EntityManager em;In the previous sections we injected resources into EJBs. You may not have been that impressed with that capability since we were already injecting EJBs without CDI. Well lets now go one step further and inject the persistence context directly into the DAOs that need the EntityManagers.
$ cat javaeeEx/pom.xml
<properties>
...
<inject.version>1</inject.version>
...
<dependencyManagement>
<dependencies>
...
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>${inject.version}</version>
</dependency>$ cat javaeeEx/javaeeExImpl/pom.xml
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<scope>provided</scope>
</dependency>$ cat javaeeExImpl/src/main/java/myorg/javaeeex/jpa/JPAPersonDAO.java
...
import javax.inject.Inject;
...
public class JPAPersonDAO implements PersonDAO {
...
private EntityManager em;
@Inject @JavaeeEx
public void setEntityManager(EntityManager em) {
this.em = em;
}$cat javaeeExImpl/src/main/java/myorg/javaeeex/blimpl/RegistrarImpl.java
...
import javax.inject.Inject;
...
public class RegistrarImpl implements Registrar {
protected PersonDAO dao;
@Inject
public void setDAO(PersonDAO dao) {$ cat javaeeExImpl/src/main/java/myorg/javaeeex/blimpl/TestUtilImpl.java
...
import javax.inject.Inject;
...
import myorg.javaeeex.cdi.JavaeeEx;
...
public class TestUtilImpl implements TestUtil {
...
@Inject @JavaeeEx
protected EntityManager em;$ cat javaeeExImpl/src/main/java/myorg/javaeeex/blimpl/TestUtilImpl.java
...
@Stateless
public class RegistrarEJB implements RegistrarLocal, RegistrarRemote {
...
@Inject
private Registrar registrar;
//@Inject @JavaeeEx
//private EntityManager em;
@PostConstruct
public void init() {
try {
log.debug("**** init ****");
//log.debug("em=" + em);
//PersonDAO dao = new JPAPersonDAO();
//((JPAPersonDAO)dao).setEntityManager(em);
//registrar = new RegistrarImpl();
//((RegistrarImpl)registrar).setDAO(dao);
log.debug("init complete, registrar=" + registrar);
}$ cat javaeeExEJB/src/main/java/myorg/javaeeex/ejb/TestUtilEJB.java
...
@Stateless
public class TestUtilEJB implements TestUtilRemote {
...
//@Inject @JavaeeEx
//private EntityManager em;
@Inject
private TestUtil testUtil;
@PostConstruct
public void init() {
log.info(" *** TestUtilEJB:init() ***");
//testUtil = new TestUtilImpl();
//((TestUtilImpl)testUtil).setEntityManager(em);
}$ mvn clean install ...
WELD-001408 Unsatisfied dependencies for type [TestUtil] with qualifiers [@Default] at injection point [[field] @Inject private myorg.javaeeex.ejb.TestUtilEJB.testUtil] WELD-001408 Unsatisfied dependencies for type [Registrar] with qualifiers [@Default] at injection point [[field] @Inject private myorg.javaeeex.ejb.RegistrarEJB.registrar]
$ touch javaeeExImpl/src/main/resources/META-INF/beans.xml
jcstaff@ubuntu:~/proj/exercises/javaeeEx$ tree javaeeExImpl/src/main/resources
javaeeExImpl/src/main/resources
`-- META-INF
|-- beans.xml
`-- orm.xmlTests run: 5, Failures: 0, Errors: 0, Skipped: 0 ... [INFO] Java EE Exercise .................................. SUCCESS [0.589s] [INFO] Java EE Exercise Impl ............................. SUCCESS [15.685s] [INFO] Java EE Exercise EJB .............................. SUCCESS [4.647s] [INFO] Java EE Exercise EAR .............................. SUCCESS [1.876s] [INFO] Java EE Exercise Remote Test ...................... SUCCESS [11.196s] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS
|-- javaeeExEJB | |-- pom.xml | |-- src | | `-- main | | |-- java | | | `-- myorg | | | `-- javaeeex | | | |-- cdi | | | | `-- ResourceConfig.java ... | | | `-- ejb | | | |-- RegistrarEJB.java | | | |-- RegistrarLocal.java | | | |-- RegistrarRemote.java | | | |-- TestUtilEJB.java | | | `-- TestUtilRemote.java | | `-- resources | | `-- META-INF | | |-- beans.xml | | `-- persistence.xml |-- javaeeExImpl | |-- pom.xml | `-- src | |-- main | | |-- java | | | `-- myorg | | | `-- javaeeex ... | | | |-- blimpl | | | | |-- RegistrarImpl.java | | | | `-- TestUtilImpl.java ... | | | |-- cdi | | | | `-- JavaeeEx.java ... | | | `-- jpa | | | |-- DBUtil.java | | | `-- JPAPersonDAO.java | | `-- resources | | `-- META-INF | | |-- beans.xml | | `-- orm.xml ...