Search code examples
jpajunitejbwebspherejava-ee-6

EntityManager not being injected in EJB module instantiated by WebSphere embeddable container while JUnit testing


My EntityManager keeps null when using embeddable container. The same code works well when invoked in a regular web application.

Test code:

package com.learning.business.car;

import static org.junit.Assert.assertEquals;
import java.util.List;
import javax.ejb.embeddable.EJBContainer;
import javax.naming.NamingException;
import org.junit.Test;

public class CarRepoTest {

    @Test
    public void testGetCarsByEjb() throws NamingException {

        EJBContainer ec = EJBContainer.createEJBContainer();

        CarRepo carRepo = (CarRepo) ec
                .getContext()
                .lookup("java:global/classes/CarRepo");

        List<Car> cars = carRepo.getAll();

        assertEquals(0, cars.size());

        ec.close();
    }
}

While debugging the above code, ec.toString() shows me:

svContainerActive = true
svNamingInitialized = true
ivContext = com.ibm.ws.naming.java.javaURLContextRoot@fe720e63[super=com.ibm.ws.naming.java.javaURLContextImpl@fe720e63[super=com.ibm.ws.naming.urlbase.UrlContextImpl(java:)@fe720e63[_schemeId=java, _primaryLeafName=null, _strCtxID=ROOT CONTEXT, _ns=com.ibm.ws.naming.ipbase.NameSpace@d2d1a4d7[_nameSpaceName=java:comp(null, null, null), _nameSpaceID=2, _nameSpaceType=1, _contextsTable=java.util.HashMap@c8fb6403[size=2], _bindingsTable=java.util.HashMap@9cd644e1[size=2]]], _javaNameSpaceScope=COMPONENT SCOPE, _jns=javaNameSpaceImpl:{_appName=null,_moduleName=null,_componentName=null,_bootstrapAddress=rir:,_clientMode=ISOLATED,_componentNameSpaceLocation=LOCAL,_otherModuleNames=[],_applicationsRootProviderURL=corbaname:rir:/NameServiceApplicationsRoot#,_applicationRootProviderURL=null,_moduleRootProviderURL=null,_componentRootProviderURL=null,_ns=com.ibm.ws.naming.ipbase.NameSpace@d2d1a4d7[_nameSpaceName=java:comp(null, null, null), _nameSpaceID=2, _nameSpaceType=1, _contextsTable=java.util.HashMap@c8fb6403[size=2], _bindingsTable=java.util.HashMap@9cd644e1[size=2]]}], _caching=false, _rootCache=com.ibm.ws.naming.java.JavaNameSpaceCache@d10b63f9]
ivIsClosed = false
ivModules = [com.ibm.websphere.ejbcontainer.EmbeddableContainer$EmbeddableModule@9202003a[name=classes, file=C:\WorkSpaceRTC\javaee6\target\classes, metadata=com.ibm.ejs.csi.SharedEJBModuleMetaDataImpl@acb40850[embeddable#classes]]]
ivProperties = {enableProtocolSecurity=false}
ivServiceTokens = [sun.misc.Launcher$AppClassLoader@f3ba9f23:interface com.ibm.ws.runtime.service.MetaDataFactoryMgr, sun.misc.Launcher$AppClassLoader@f3ba9f23:interface com.ibm.wsspi.injectionengine.InjectionEngine]

EJB module:

package com.learning.business.car;

import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;

@Stateless
public class CarRepo {

    @PersistenceContext
    protected EntityManager em;

    public List<Car> getAll() {

        // "em" keeps null and the below line throws a NullPointerException
        TypedQuery<Car> query = em.createQuery("SELECT c FROM Car c", Car.class);

        return query.getResultList();
    }
}

persistence.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<persistence 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"
    version="2.0">

    <persistence-unit name="javaee6" transaction-type="JTA">
        <class>com.learning.business.car.Car</class>

        <properties>
            <property name="javax.persistence.jdbc.driver" value="org.h2.Driver" />
            <property name="javax.persistence.jdbc.url" value="jdbc:h2:mem:test;DB_CLOSE_DELAY=-1" />
            <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>
        </properties>
    </persistence-unit>
</persistence>

Exception:

CNTR0020E: EJB threw an unexpected (non-declared) exception during invocation of method "getAll" on bean "BeanId(embeddable#classes#CarRepo, null)". Exception data: java.lang.NullPointerException
    at com.learning.business.car.CarRepo.getAll(CarRepo.java:18)
    at com.learning.business.car.EJSLocalNSLCarRepo_a1ab5865.getAll(EJSLocalNSLCarRepo_a1ab5865.java)
    at com.learning.business.car.CarRepoTest.testGetCarsByEjb(CarRepoTest.java:23)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:60)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
    at java.lang.reflect.Method.invoke(Method.java:611)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:73)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:46)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:180)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:41)
    at org.junit.runners.ParentRunner$1.evaluate(ParentRunner.java:173)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:220)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

On the other hand, the below code works when consumed by a xhtml page in a WebSphere application:

package com.learning.app.car;

import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import com.learning.business.car.CarRepo;

@ManagedBean
public class CarBean {

    @EJB
    public CarRepo carRepo;

    public Integer getCarsCount() {

        // in a WebSphere application it works as expected (EntityManager is correctly injected in CarRepo)
        return carRepo.getAll().size();
    }
}

Solution

  • It is suggested to include JPA thin client when you use embeddable container. Check the following link for details maybe it will help you Running an embeddable container

    When developing an application using JPA in the embeddable EJB container, the class path must include the JPA thin client, com.ibm.ws.jpa.thinclient_n.0.jar, where n is the WebSphere® Application Server release; for example, 8.5 for Version 8.5. The JPA thin client is located in \runtimes where the root directory of the installation image is located.