【问题标题】:Cannot inject EntityManager declared in persistence.xml无法注入在 persistence.xml 中声明的 EntityManager
【发布时间】:2014-07-23 13:06:28
【问题描述】:

我正在尝试开发一个(基于 Maven 的)jar 库,它可以充当我的 Java 应用程序的 DAL。

这是我的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="DALPersistenceUnit" transaction-type="JTA">
      <provider>org.hibernate.ejb.HibernatePersistence</provider>
      <jta-data-source>java:app/env/MyDataSource</jta-data-source>          
      <shared-cache-mode>NONE</shared-cache-mode>
      <properties>
         <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
      </properties>
   </persistence-unit>
</persistence>

这是DataSource 定义,使用@DataSourceDefinition 注释完成

import javax.annotation.sql.DataSourceDefinition;
import javax.ejb.Startup;


@DataSourceDefinition(name = "java:app/env/MyDataSource",
                      className = "com.mysql.jdbc.Driver",
                      serverName="<serverIP>",
                      portNumber=3306,
                      user = "<username>",
                      password = "<pwd>",
                      databaseName = "<dbname>",
                      minPoolSize = 0,
                      initialPoolSize = 0
                      )
@Startup
public class MyDataSource {

}

这是从persistence.xml 定义中检索EntityManager 的DAO(我使用QueryDSL 来简化查询定义)

package my.dal.dao;
import my.domain.dal.QUser;
import my.domain.dal.User;

import javax.enterprise.inject.Default;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;

import com.mysema.query.jpa.JPQLQuery;
import com.mysema.query.jpa.impl.JPAQuery;

@Default
public class UserDAO {

    @PersistenceContext(unitName = "DALPersistenceUnit", type = PersistenceContextType.EXTENDED)
    private EntityManager entityManager;

    public User getMark()
    {
        QUser qUser = QUser.user;
        JPQLQuery query = new JPAQuery(entityManager);          
        User mark = query.from(qUser).where(qUser.username.eq("mark")).uniqueResult(qUser);
        return mark;
    }       
}

另外,我在META-INF 文件夹中添加了beans.xml 文件

<?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
   http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">

</beans>

这是测试类(我使用CDI-Unit 进行 CDI 测试)

import my.dal.dao.UserDAO;
import my.domain.dal.User;
import static org.junit.Assert.assertTrue;
import javax.inject.Inject;
import org.jglue.cdiunit.CdiRunner;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(CdiRunner.class)
public class DALUserTest {

    @Inject UserDAO userDAO;

    @Test
    public void testGetMark()
    {
        User user = userDAO.getMark(); // Here I get a NullPointerException
        assertTrue(user.getUsername()=="mark");
    }
}

当我运行测试时,我在测试类的标记行处得到一个 NullPointerException。此外,如果我调试测试,我可以看到UserDAO 类的EntityManager entityManager 字段是null,所以它不是从persistence.xml 文件中注入的。

我是否遗漏了 Java 持久性/CDI 机制中的某些内容?

谢谢

编辑 1:我已将 Maven 依赖项添加到

querydsl-core:3.3.2
querydsl-apt:3.3.2
querydsl-jpa:3.3.2
log4j:1.2.16
mysql-connector-java:5.1.29
hibernate-entitymanager:4.3.1.Final
hibernate-validator:5.0.3.Final
cdi-unit:3.0.1
junit:4.11
javaee-api:7.0
hibernate-jpa-2.0-api:1.0.1.Final
hibernate-core:4.3.1.Final
hibernate-commons-annotations:4.0.4.Final

编辑 2:按照 @earthling 的建议,我在 beans.xml 文件中添加了以下 bean 定义

<bean id="entityManagerFactory" class="org.hibernate.jpa.internal.EntityManagerFactoryImpl">
    <property name="persistenceUnitName" value="DALPersistenceUnit" />
    <property name="persistenceXmlLocation" value="classpath*:/src/main/resources/META-INF/persistence.xml" />
</bean> 

但我在beans.xml 文件中收到以下错误

cvc-complex-type.2.4.a:发现无效内容以 元素“豆”。之一 '{"http://java.sun.com/xml/ns/javaee":拦截器, "http:// java.sun.com/xml/ns/javaee":装饰器, 应为“http://java.sun.com/xml/ns/javaee”:alternatives}'。

【问题讨论】:

    标签: java jpa persistence.xml cdi-unit


    【解决方案1】:

    尝试在您的 bean xml 中创建 entityManagerFactory 并通过构造函数注入注入您的 DAO 类

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
             <property name="persistenceUnitName" value="DALPersistenceUnit" />
            <property name="persistenceXmlLocation" value="classpath*:/<path-to>/persistence.xml" />
    </bean> 
    

    【讨论】:

    • 你应该为此创建一个默认构造函数..或者使用setter注入并添加entityManager的setter方法..
    • OP 不使用 Spring...检查他的 Maven 依赖项。 beans.xml 用于 CDI。
    • 那么,我应该使用另一个 EntityManagerFactory 类吗?哪一个?
    【解决方案2】:

    您正在配置数据源两次。在persistence.xml 中并通过@DataSourceDefinition

    由于您没有在应用程序服务器中运行测试,因此您需要produce an EntityManager yourself。一个好主意是使用一个 EntityManagerProducer ,它可以切换为运行测试的替代方案。

    @RequestScoped
    public class EntityManagerProvider {
    
        @PersistenceContext
        private EntityManager entityManager;
    
        @Produces
        public EntityManager getEntityManager() {
            return entityManager;
        }
    
    }
    

    那么你需要一个Test-EntityManager Producer

    @Alternative
    @RequestScoped
    public class EntityManagerProvider {
    
    
        private EntityManager entityManager;
    
        @Produces
        public EntityManager getEntityManager() {
            if(entityManager == null) {
                EntityManagerFactory emf = Persistence.createEntityManagerFactory("...");
                entityManager = emf.createEntityManager();
            }
            return entityManager;
        }
    
    }
    

    您可以通过这种方式访问​​您的 EntityManager @Inject private EntityManager em

    【讨论】:

    • 我正在开发的 jar 库将集成在一个 Web 应用程序中,该应用程序将在 Wildfly (JBoss AS 8) 上运行,因此最终该库将在应用程序服务器中运行。即使在这种情况下,我是否还需要编写 EntityManagerProvider 类?
    • 这个类只是为你的测试提供一个EntityManager,因为它们不在应用服务器上运行。
    • 好的。我添加了您提供的代码,但在注入点我收到此警告消息“没有 bean 有资格注入到注入点 [JSR-299 §5.2.1]”。如果我尝试运行测试,它将停止抛出此异常pastebin.com/CnQmxj7Y
    • 我添加了对替代 EntityManagerProvider 的返回。您能否通过调用 getEntityManager 并将某些内容持久化到数据库中来验证该类是否正常工作?
    • 尝试像 cdi-uni 的文档中那样添加替代的 EntityManagerProvider:` @RunWith(CdiRunner.class) @AdditionalClasses(WarpDrive.class) // WarpDrive 可以使用。类 TestStarship { `
    猜你喜欢
    • 2014-07-17
    • 1970-01-01
    • 2012-01-11
    • 1970-01-01
    • 2016-08-06
    • 2017-05-28
    • 2012-08-29
    • 1970-01-01
    • 2012-05-24
    相关资源
    最近更新 更多