简体   繁体   中英

Error Injecting the JPA Entity Manager in WebSphere Liberty

I have inherited a legacy application that initially was built with WebSphere 6.1 and then was migrated to WebSphere 8.0 running with JPA 2.0 and openJPA without issues. We are migrating to WebSphere Liberty for strategic reasons. We first tested on WebSphere Classic 8.5.5.8 and JPA and the entity manger has no issues there. However, on Liberty 8.5.5.8 I get the following exception:

javax.ejb.EJBException: The java:comp/env/com.xxx.xxxx.service.CHServiceBean/em reference of type javax.persistence.EntityManager for the CHServiceBean component in the CHServiceEJB.jar module of the CHServiceEAR application cannot be resolved. at com.ibm.wsspi.injectionengine.InjectionBinding.getInjectionObject(InjectionBinding.java:1493) ..... [err] Caused by: [err] javax.ejb.EJBException: The java:comp/env/com.xxxx.xxxx.service.CHServiceBean/em reference of type javax.persistence.EntityManager for the CHServiceBean component in the CHServiceEJB.jar module of the CHServiceEAR application cannot be resolved. [err] at com.ibm.wsspi.injectionengine.InjectionBinding.getInjectionObject(InjectionBinding.java:1493) [err] at [internal classes]

I had another EJB injection issue that was resolved through configuration of the binding files, however I am unable to resolve this issue. I have two applications that each have their own EAR files but both run in the same Liberty JVM. Application A runs the front end/UI logic while Application B is the back-end EJB / JPA interfaces. In the project facets the JPA application is set to 2.0 (I wanted 2.1 but based on another thread JPA 2.0 and EJB 3.1 are as high as I can go at the moment...See my other thread topic here --> Eclipse Juno and JPA 2.1 support ).

Here is my server.xml file:

    <server description="new server">

    <!-- Enable features -->
    <featureManager>
        <feature>javaee-7.0</feature>
        <feature>localConnector-1.0</feature>
        <feature>distributedMap-1.0</feature>
        <feature>adminCenter-1.0</feature> 
        <feature>ssl-1.0</feature>
        <feature>usr:webCacheMonitor-1.0</feature>
        <feature>webCache-1.0</feature>
        <feature>ldapRegistry-3.0</feature>
    </featureManager>

    <!--  Admin Center Config Start -->
    <!-- To access this server from a remote client add a host attribute to the following element, e.g. host="*" -->
    <httpEndpoint host="*" httpPort="9080" httpsPort="9443" id="defaultHttpEndpoint"/>

    <keyStore id="defaultKeyStore" password="xxxxxx"/> 

    <basicRegistry id="basic"> 
          <user name="admin" password="xxxxx"/> 
          <user name="nonadmin" password="xxxxxx"/> 
    </basicRegistry> 

    <administrator-role> 
      <user>admin</user>
    </administrator-role>

    <remoteFileAccess> 
       <writeDir>${server.config.dir}</writeDir> 
    </remoteFileAccess>

    <!-- Automatically expand WAR files and EAR files -->
    <applicationManager autoExpand="true"/>
    <applicationMonitor updateTrigger="mbean"/>

    <enterpriseApplication id="CHNewCHRDMEAR" location="CHNewCHRDMEAR.ear" name="CHNewCHRDMEAR">
        <application-bnd>
            <security-role name="AllAuthenticated">
                <special-subject type="ALL_AUTHENTICATED_USERS"/>
            </security-role>
        </application-bnd>
    </enterpriseApplication>
    <enterpriseApplication id="CHServiceEAR" location="CHServiceEAR.ear" name="CHServiceEAR"/>

    <!--  JAAS Authentication Alias (Global) Config -->
    <authData id="dbUser" password="{xor}MzhmJT06ajI=" user="dbUser"/>

    <!--  JDBC Driver and Datasource Config -->
    <library id="DB2JCC4Lib">
        <fileset dir="C:\DB2\Jars" includes="db2jcc4.jar db2jcc_license_cisuz.jar"/>
    </library>

    <dataSource containerAuthDataRef="dbUser" id="CHTEST2" jndiName="jdbc/nextgen" type="javax.sql.XADataSource">
        <jdbcDriver libraryRef="DB2JCC4Lib"/>
        <properties.db2.jcc databaseName="CHTEST2" password="{xor}MzhmJT06ajI=" portNumber="60112" serverName="server.com" sslConnection="false" user="dbUser"/>
        <containerAuthData password="{xor}MzhmJT06ajI=" user="dbUser"/>
    </dataSource>

    <dataSource id="CHTEST2_RO" jndiName="jdbc/nextgen_RO" type="javax.sql.XADataSource">
        <jdbcDriver libraryRef="DB2JCC4Lib"/>
        <properties.db2.jcc databaseName="CHTEST2" password="{xor}MzhmJT06ajI=" portNumber="60112" serverName="server.com" sslConnection="false" user="dbUser"/>
        <containerAuthData password="{xor}MzhmJT06ajI=" user="dbUser"/>
    </dataSource>
<!-- More in file, but no included...-->
</server>

Here is my persistence.xml file:

<?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="CHService" transaction-type="JTA">
    <jta-data-source>jdbc/nextgen</jta-data-source>
    <exclude-unlisted-classes>true</exclude-unlisted-classes>
    <properties>
        <property name="openjpa.jdbc.TransactionIsolation" value="read-uncommitted" /></properties></persistence-unit>
    <persistence-unit name="CHServiceRO" transaction-type="JTA">
        <jta-data-source>jdbc/nextgen_RO</jta-data-source>
        <exclude-unlisted-classes>true</exclude-unlisted-classes>
        <properties>
            <property name="openjpa.jdbc.TransactionIsolation" value="read-uncommitted" />
</properties>
</persistence-unit>
</persistence>

I *believe that we are relying solely on injection to get the context for JPA jndi lookups but that is because I don't see in our code any call to an initial context for any JPA specific JNDI names. Below are my two anotated session beans from the EJB project:

a. The CHService Bean:

    @Stateless
@TransactionManagement(TransactionManagementType.CONTAINER)
@Local({ CHServiceLocal.class })
@Remote({ CHServiceRemote.class })
@Interceptors({ CHServiceLog.class })
@Resources({
        @Resource(name = "jdbc/nextgen", mappedName = "jdbc/nextgen", authenticationType = AuthenticationType.APPLICATION, shareable = true, type = javax.sql.DataSource.class),
        @Resource(name = "services/cache/CHBluepages", mappedName = "services/cache/CHBluepages", authenticationType = AuthenticationType.APPLICATION, shareable = true, type = com.ibm.websphere.cache.DistributedMap.class),
        @Resource(name = "services/cache/CHGeneric", mappedName = "services/cache/CHGeneric", authenticationType = AuthenticationType.APPLICATION, shareable = true, type = com.ibm.websphere.cache.DistributedMap.class) })
public class CHServiceBean extends AbstractCHServiceImpl implements
        CHService {

    @PersistenceContext(unitName = "CHService")
    private EntityManager em;

b. The CHServiceRO bean:

@Stateless
@TransactionManagement(TransactionManagementType.CONTAINER)
@Local({CHServiceLocalRO.class})
@Remote({CHServiceRemoteRO.class})
@Interceptors({CHServiceROLog.class})
@Resources({
    @Resource(name="jdbc/nextgen_RO", mappedName="jdbc/nextgen_RO", authenticationType=AuthenticationType.APPLICATION, shareable=true, type=javax.sql.DataSource.class),
    @Resource(name="jdbc/nextgen", mappedName="jdbc/nextgen", authenticationType=AuthenticationType.APPLICATION, shareable=true, type=javax.sql.DataSource.class),
    @Resource(name="services/cache/CHBluepages", mappedName="services/cache/CHBluepages", authenticationType=AuthenticationType.APPLICATION, shareable=true, type=com.ibm.websphere.cache.DistributedMap.class),
    @Resource(name="services/cache/CHGeneric", mappedName="services/cache/CHGeneric", authenticationType=AuthenticationType.APPLICATION, shareable=true, type=com.ibm.websphere.cache.DistributedMap.class)
})
public class CHServiceBeanRO implements CHServiceRO {

    @PersistenceContext (unitName="CHServiceRO") private EntityManager em;

    private CHServiceBase ch;

    @PostConstruct
    private void init() { ch = new CHServiceBase(em); }

Here is a snippet from the Web.xml of the front-end application calling the JPA application:

<resource-ref id="ResourceRef_1436377001246">
        <res-ref-name>jdbc/nextgen</res-ref-name>
        <res-type>javax.sql.DataSource</res-type>
        <res-auth>Application</res-auth>
        <res-sharing-scope>Shareable</res-sharing-scope>
    </resource-ref>
    <resource-ref id="ResourceRef_1436377001247">
        <res-ref-name>jdbc/nextgen_RO</res-ref-name>
        <res-type>javax.sql.DataSource</res-type>
        <res-auth>Application</res-auth>
        <res-sharing-scope>Shareable</res-sharing-scope>
    </resource-ref>

Based on the post from Gas on this topic: java.lang.ClassCastException,Getting Entitymanager Via JNDI Lookup

I also tried updating the web.xml with the following entries:

<persistence-unit-ref>
  <persistence-unit-ref-name>chJPA</persistence-unit-ref-name>
  <persistence-unit-name>CHService</persistence-unit-name>
</persistence-unit-ref>
<persistence-unit-ref>
  <persistence-unit-ref-name>chJPA_RO</persistence-unit-ref-name>
  <persistence-unit-name>CHServiceRO</persistence-unit-name>
</persistence-unit-ref>

and the Bean code with:

@PersistenceContext(name = "chJPA", unitName = "CHService")

and

@PersistenceContext (name="chJPA_RO", unitName="CHServiceRO")

Got the same error just with a different jndi name, ie The java:comp/env/chJPA reference of type javax.persistence.EntityManager for the CHServiceBean com.......etc etc.

Lastly, per this post: Error while accessing EntityManager - openjpa - WAS liberty profile It seems that maybe I can't have the full JavaEE 7 feature and run JPA 2.0? Please advise!

As in the post you are referring to - you cannot have <feature>javaee-7.0</feature> together with JPA 2.0, as it enables 2.1, thats why you have conflicts.

So you have 2 options:

  • either use Java EE7 and JPA 2.1
  • or just enable required Java EE 6 features and then use JPA 2.0

Since you are migrating from WAS 8.0, which doesn't support Java EE7 for now, easier choice might be to use the second option. So try to remove javee-7.0 feature, and add ejbLite-3.1 and jpa-2.0 and whatever you need more.

You are correct that you cannot have javaee-7.0 and the JPA 2.0 feature, as it enables the JPA 2.1 feature. So the answer Gas gave is correct.

I just wanted to point out since you said that you do want to go to JPA 2.1 eventually, once you work out your eclipse issues, that you should use the WebSphere Application Server Migration Toolkit to identify application changes needed when migrating from JPA 2.0 to JPA 2.1. The Liberty JPA 2.0 implementation is built on OpenJPA, whereas the JPA 2.1 implemtation is built on EclipseLink. The migration toolkit is downloadable for free on wasdev: https://developer.ibm.com/wasdev/downloads/#asset/tools-WebSphere_Application_Server_Migration_Toolkit

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM