Невозможно внедрить EntityManager, объявленный в файле persistence.xml.
Я пытаюсь разработать библиотеку jar (на основе Maven), которая может служить DAL для моего Java-приложения.
Это мое 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 {
}
Это DAO, который извлекает EntityManager
от persistence.xml
определение (я использую 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;
}
}
Кроме того, я добавил beans.xml
файл в META-INF
папка
<?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 в отмеченной строке в тестовом классе. Более того, если я отлаживаю тест, я вижу, что EntityManager entityManager
поле UserDAO
класс null
, поэтому он не вводится из persistence.xml
файл.
Я что-то упускаю в механизме персистентности /CDI Java?
Спасибо
РЕДАКТИРОВАТЬ 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.xm
л файл
<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: Обнаружено недопустимое содержимое, начиная с элемента 'bean'. Один из '{" http://java.sun.com/xml/ns/javaee": interceptors, "http: // java.sun.com/xml/ns/javaee":decorators," http://java.sun.com/xml/ns/javaee": альтернативы}'ожидается.
2 ответа
Вы настраиваете свой источник данных дважды. В файле persistence.xml и через @DataSourceDefinition
,
Поскольку вы не запускаете свои тесты на сервере приложений, вам необходимо создать EntityManager самостоятельно. Хорошей идеей было бы использовать EntityManagerProducer, который можно переключать с помощью альтернативы для запуска тестов.
@RequestScoped
public class EntityManagerProvider {
@PersistenceContext
private EntityManager entityManager;
@Produces
public EntityManager getEntityManager() {
return entityManager;
}
}
Тогда вам нужен производитель Test-EntityManager
@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
Попробуйте создать entityManagerFactory в своем XML-компоненте и внедрить его в класс 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>