How to inject SessionFactory when persistence unit is defined? - java

I have a fully working Spring 4 + Hibernate application. Hibernate is configured via <persistence-unit>... My unit test does all DB-related work without a problem. But now I want to access Hibernate session; to do that I should inject SessionFactory. How to inject it considering the following configuration?
I know I could define a bean like LocalSessionFactoryBean but don't know how to configure it. (I want no duplicated aconfiguration also.)
MyTest.java
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:META-INF/spring/test-context.xml" })
#TestExecutionListeners({ DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class, TransactionalTestExecutionListener.class})
public class MyTest {
#Inject
SessionFactory sessionFactory; // want it injected
}
test-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<context:annotation-config/>
<context:component-scan base-package="com.mycompany"/>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="hibernateJpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter"/>
<property name="persistenceUnitName" value="my-persistence-unit"/>
</bean>
</beans>
persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="..." version="2.0">
<persistence-unit name="my-persistence-unit" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:jboss/datasources/my</jta-data-source>
<class>com.mycompany.entity.Document</class>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect"/>
<property name="hibernate.hbm2ddl.auto" value="validate"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="false"/>
<property name="hibernate.archive.autodetection" value="class, hbm"/>
<property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform"/>
</properties>
</persistence-unit>
</persistence>

Because I use JPA I should inject EntityManager, not SessionFactory. This solved my task finally.
#PersistenceContext
private EntityManager entityManager;
...
entityManager.refresh(obj); // working with H-session
...
This is exactly by the #m-deinum's comment; if he will add his own answer then I'll mark it as decision.

Related

No EntityManager with actual transaction available for current thread - cannot reliably process 'persist'

While doing insert operation on my web service which is deployed on Tomcat I am facing following exception
javax.persistence.TransactionRequiredException: No EntityManager with
actual transaction available for current thread - cannot reliably
process 'persist' call
My spring-jpa.xml is as follows
<?xml version="1.0" encoding="UTF-8"?>
<!-- ========================= RESOURCE DEFINITIONS ========================= -->
<!-- Activates a load-time weaver for the context. Any bean within the context that implements LoadTimeWeaverAware
(such as LocalContainerEntityManagerFactoryBean) will receive a reference to the autodetected load-time weaver. -->
<context:load-time-weaver aspectj-weaving="on" weaver-class="org.springframework.instrument.classloading.tomcat.TomcatLoadTimeWeaver" />
<bean id="entityManagerFactoryReadOnly" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="ReadOnlyBasePersistenceUnit" />
</bean>
<bean id="entityManagerFactoryReadWrite" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="ReadWriteBasePersistenceUnit" />
</bean>
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter" />
<bean id="transactionManagerReadOnly" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactoryReadOnly" />
<property name="defaultTimeout" value="90" />
</bean>
<bean id="transactionManagerReadWrite" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactoryReadWrite" />
<property name="defaultTimeout" value="90" />
</bean>
<!-- ========================= BUSINESS OBJECT DEFINITIONS ========================= -->
<!-- Instruct Spring to perform declarative transaction management automatically on annotated classes. -->
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManagerReadWrite"/>
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManagerReadOnly"/>
<!-- Post-processor to perform exception translation on #Repository classes (from native exceptions such
as JPA PersistenceExceptions to Spring's DataAccessException hierarchy). -->
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
</beans>
dependecncies.gradle is as follows
compile (
'commons-lang:commons-lang:2.2',
'javax.xml:jsr173:1.0',
'commons-httpclient:commons-httpclient:3.1',
'javax.servlet:servlet-api:2.5',
'regexp:regexp:1.3',
'org.aspectj:aspectjrt:1.8.4',
'org.aspectj:aspectjweaver:1.8.4',
'org.springframework:spring-aspects:5.0.0.RELEASE',
'org.springframework:spring-jdbc:5.0.0.RELEASE',
'org.springframework:spring-jms:5.0.0.RELEASE',
'org.springframework:spring-orm:5.0.0.RELEASE',
'org.springframework:spring-oxm:5.0.0.RELEASE',
'org.springframework:spring-web:5.0.0.RELEASE',
'org.springframework:spring-webmvc:5.0.0.RELEASE',
'org.springframework:spring-instrument-tomcat:4.0.9.RELEASE'
'javax.persistence:javax.persistence-api:2.2',
'org.eclipse.persistence:eclipselink:2.5.2'
}
Service class is as follows
class Facade impelments Ifacade {
#Autowired
private MyDao dao
#Override
#Transactional
public CreateRequestResponse createRequests(List<BusinnessObject> bobject) {
this.dao.createRequests(bobject)
}
}
My persistence.xml is as follows
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0"
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_1_0.xsd">
<persistence-unit name="ReadOnlyBasePersistenceUnit" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<non-jta-data-source>jdbc/DS_RW</non-jta-data-source>
<class>com.temp.request.model.dataobject.RqstOne</class>
<class>com.temp.request.model.dataobject.RqstTwo</class>
<class>com.temp.request.model.dataobject.RqstThree</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="eclipselink.target-server" value="com.temp.request.tomcat.TomcatPlatform"/>
<property name="eclipselink.target-database" value="org.eclipse.persistence.platform.database.oracle.Oracle11Platform" />
<property name="eclipselink.logging.level" value="WARNING" />
<property name="eclipselink.persistence-context.flush-mode" value="COMMIT" />
<property name="eclipselink.persistence-context.close-on-commit" value="true" />
<property name="eclipselink.cache.shared.default" value="false" />
</properties>
</persistence-unit>
<persistence-unit name="ReadWriteBasePersistenceUnit" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<non-jta-data-source>jdbc/DS_RW</non-jta-data-source>
<class>com.temp.request.model.dataobject.RqstOne</class>
<class>com.temp.request.model.dataobject.RqstTwo</class>
<class>com.temp.request.model.dataobject.RqstThree</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="eclipselink.target-server" value="com.temp.request.tomcat.TomcatPlatform"/>
<property name="eclipselink.target-database" value="org.eclipse.persistence.platform.database.oracle.Oracle11Platform" />
<property name="eclipselink.logging.level" value="WARNING" />
<property name="eclipselink.persistence-context.flush-mode" value="COMMIT" />
<property name="eclipselink.persistence-context.close-on-commit" value="true" />
<property name="eclipselink.cache.shared.default" value="false" />
</properties>
</persistence-unit>
</persistence>

Entity Manager null everytime on running Junit tests

I am new to Spring and JPA. I developed a project using Spring4 , spring scheduler and JPA and now I want to test my code using Junit test cases. I started with testing my DAO methods. Here is the source code:
This class does the triggering task for the scheduler
public class TriggerTask {
#Autowired
private TriggerDaoBean triggerDaoBean;
public void executeDailyTask() {
try{
List<User> users=triggerDaoBean.getClients();
if (null != users && users.size()>0){
//do some task
}
}catch(Exception e){
}
}}
The DAO bean is :
#Stateless
public class TriggerDaoBean implements Serializable {
private static final long serialVersionUID = 1L;
#PersistenceContext
private EntityManager em;
public List<User> getUsers() {
List<User> userList = new ArrayList<User>();
Query query = em.createQuery(
"SELECT user FROM USER user");
userList = (List<User>)query.getResultList();
if (null != userList && userList.size() > 0) {
return userList;
} else {
return null;
}
}
....
}
I wrote the below test case:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "/spring-quartz-test.xml" })
#TransactionConfiguration(defaultRollback=true)
#Transactional
public class TriggerTest {
#Autowired
TriggerDaoBean triggerDaoBean;
#Test
public void getUserListTest() {
triggerDaoBean.getUsers();
}
}
The content of spring-quartz-test.xml is as follows:
<bean id="triggerTask" class="com.test.service.TriggerTask">
<property name="triggerDaoBean" ref="triggerDaoBean"/>
</bean>
<bean id="triggerDaoBean"
class="com.test.service.TriggerDaoBean">
</bean>
<bean id="runsrJobDaily" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="triggerTask" />
<property name="targetMethod" value="executeDailyTask" />
</bean>
And the persistence.xml is as follows:
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="forge-default" transaction-type="JTA" >
<description>Forge Persistence Unit</description>
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:/MySqlDS</jta-data-source>
<class>com.test.persistence.entity.User</class>
<properties>
<!-- <property name="hibernate.hbm2ddl.auto" value="create-drop"/> -->
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
<!--
<property name="hibernate.ejb.cfgfile" value="modified.hibernate.cfg.xml"/>
-->
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.transaction.flush_before_completion" value="true"/>
</properties>
</persistence-unit>
</persistence>
java:/MySqlDS is the JNDI name of datasource.
Everytime I run my test, NullPointerException comes for the EntityManager.
Am I doing something wrong?
I'm my case, you need to append two annotations on your test class.
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
#RunWith(SpringRunner.class)
#SpringBootTest(classes = SpringBootApplicationClass.class)
You have to define your entityManager in spring, I do not see the entityManager in the code you posted, you can do it in this way
<tx:annotation-driven transaction-manager="txManager"/>
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="example" />
</bean>
<bean id="entityManager" class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
Be aware that your are defining your transaction type as JTA in persistence.xml, really do you need global transactions? if not, delete transaction-type="JTA" in persistence.xml
Another thing, for test purposes would be better to use a test database like H2. You can define it in test spring context inside src/test/resources
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation" value="classpath:META-INF/persistence-test.xml"/>
<property name="persistenceUnitName" value="example-test" />
<property name="dataSource" ref="dataSourceTest"/>
</bean>
<bean id="entityManager" class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="dataSourceTest" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
<property name="driverClass" value="org.h2.Driver"/>
<property name="url" value="jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
</bean>
<bean id="org.h2.tools.Server-WebServer" class="org.h2.tools.Server"
factory-method="createWebServer" init-method="start" lazy-init="true">
<constructor-arg value="-web,-webAllowOthers,-webPort,11111" />
</bean>
this way you can control the database state, each test will create a database in memory, you can define an import.sql in src/test/resource in order to fill your tables with test data. You have to add de h2 dependency in pom.xml
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.3.174</version>
<scope>test</scope>
</dependency>

Multiple persistence unit in persistence.xml file with JPA 2.1

I am trying to deploy an application that connects to Oracle Database and MySQL. I am using JPA 2.1, Hibernate 4.3.7, Spring, Spring Data and WildFly 8.2 but I am getting some errors when deploying the application. Eclipse shows error. He says that I cannot use more than one persistence unit. I was confused because I found some articles on the web showing files with more than one persistence unit. Like this one.
First of all my persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://www.oracle.com/webfolder/technetwork/jsc/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="authwsPU" transaction-type="JTA">
<jta-data-source>java:/datasource/authwsds</jta-data-source>
..My MySQL mapping classes...
<properties>
<!-- MySQL -->
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.hbm2ddl.auto" value="update"/>
<property name="hibernate.id.new_generator_mappings" value="true"/>
<property name="jboss.entity.manager.factory.jndi.name" value="java:jboss/authwsEMF" />
</properties>
</persistence-unit>
<persistence-unit name="antaresPU" transaction-type="JTA">
<jta-data-source>java:/datasource/antaresds</jta-data-source>
...My Oracle mapping classes...
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.id.new_generator_mappings" value="true"/>
<property name="jboss.entity.manager.factory.jndi.name" value="java:jboss/antaresEMF" />
</properties>
</persistence-unit>
</persistence>
I made change on jboss-web.xml too:
<?xml version="1.0" encoding="UTF-8"?>
<jboss-web xmlns="http://www.jboss.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee
http://www.jboss.org/j2ee/schema/jboss-web_5_1.xsd">
<context-root>/authws</context-root>
<persistence-context-ref id="autenticacaoCtx">
<persistence-context-ref-name>auth_ws/authEMF</persistence-context-ref-name>
<persistence-unit-name>authwsPU</persistence-unit-name>
</persistence-context-ref>
<persistence-context-ref id="antaresCtx">
<persistence-context-ref-name>auth_ws/antaresEMF</persistence-context-ref-name>
<persistence-unit-name>antaresPU</persistence-unit-name>
</persistence-context-ref>
</jboss-web>
And the errors. Eclipse, warned me, but I ignored.:
Multiple persistence units defined - only the first persistence unit will be recognized
Then I deployed and WildFly shows this error:
Caused by: java.lang.IllegalArgumentException: JBAS011470: Persistence unitName was not specified and there are 2 persistence unit definitions in application deployment deployment "authws.war". Either change the application deployment to have only one persistence unit definition or specify the unitName for each reference to a persistence unit.
at org.jboss.as.jpa.container.PersistenceUnitSearch.ambiguousPUError(PersistenceUnitSearch.java:187)
at org.jboss.as.jpa.container.PersistenceUnitSearch.findWithinDeployment(PersistenceUnitSearch.java:153)
at org.jboss.as.jpa.container.PersistenceUnitSearch.findPersistenceUnitSupplier(PersistenceUnitSearch.java:75)
at org.jboss.as.jpa.container.PersistenceUnitSearch.resolvePersistenceUnitSupplier(PersistenceUnitSearch.java:64)
at org.jboss.as.jpa.processor.JPAAnnotationProcessor.getPersistenceUnit(JPAAnnotationProcessor.java:372)
at org.jboss.as.jpa.processor.JPAAnnotationProcessor.getBindingSource(JPAAnnotationProcessor.java:296)
at org.jboss.as.jpa.processor.JPAAnnotationProcessor.processMethod(JPAAnnotationProcessor.java:206)
at org.jboss.as.jpa.processor.JPAAnnotationProcessor.processPersistenceAnnotations(JPAAnnotationProcessor.java:143)
at org.jboss.as.jpa.processor.JPAAnnotationProcessor.deploy(JPAAnnotationProcessor.java:100)
at org.jboss.as.server.deployment.DeploymentUnitPhaseService.start(DeploymentUnitPhaseService.java:159) [wildfly-server-8.2.0.Final.jar:8.2.0.Final]
... 5 more
UPDATE
I am updating the question with more details. First, the file where I create the EntityManagersFactory for Spring Data:
<jee:jndi-lookup jndi-name="java:jboss/poEMF" id="poEntityManagerFactory" expected-type="javax.persistence.EntityManagerFactory" />
<jpa:repositories base-package="br.com.po.dao" entity-manager-factory-ref="poEntityManagerFactory" />
<jee:jndi-lookup jndi-name="java:jboss/antaresEMF" id="antaresEntityManagerFactory" expected-type="javax.persistence.EntityManagerFactory" />
<jpa:repositories base-package="br.com.antares.dao" entity-manager-factory-ref="antaresEntityManagerFactory" />
Reading more about this online, I saw that the problem can be specification of the annotation #PersistenceUnit where I have to specify the unitName like #PersistenceUnit(unitName="defaultPersistenceUnit"). But, how I do this if I am using Spring Data?
For example you can use #EnableJpaRepositories in your #Configuration files (if you are using Bean Configuration) like this:
One configuration file with:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
basePackages = {"com.yourpackage.xxxx"},
entityManagerFactoryRef = "entityManagerFactory1",
transactionManagerRef = "transactionManager")
public class FirstPersistenceContextConfig {}
....
And a second configuration file:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
basePackages = {"com.yourpackage.yyyy"},
entityManagerFactoryRef = "entityManagerFactory2",
transactionManagerRef = "transactionManager")
public class SecondPersistenceContextConfig {}
...
I don't know if you've solved your problem.
If you're using a XML configuration, try this:
<jpa:repositories base-package="[repository]"
entity-manager-factory-ref="mysqlManager" transaction-manager-ref="mysqlTransaction"/>
<jpa:repositories base-package="[repository]"
entity-manager-factory-ref="oracleManager" transaction-manager-ref="oracleTransaction"/>
<bean id="mysqlDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<!-- MySQL Configuration Connection -->
</bean>
<bean id="mysqlTransaction" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="mysqlManager" />
</bean>
<bean id="mysqlManager" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="mysqlDataSource" />
<property name="persistenceUnitName" value="mysqlPU" />
<property name="packagesToScan" value="lh.ast.model" />
<property name="persistenceProviderClass" value="org.hibernate.ejb.HibernatePersistence"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
<property name="showSql" value="true" />
</bean>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<bean id="oracleDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<!-- Oracle Configuration Connection -->
</bean>
<bean id="oracleTransaction" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="oracleManager" />
</bean>
<bean id="oracleManager" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="oracleDataSource" />
<property name="persistenceUnitName" value="oraclePU" />
<property name="packagesToScan" value="[your entity package]" />
<property name="persistenceProviderClass" value="org.hibernate.ejb.HibernatePersistence"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect" />
<property name="showSql" value="true" />
</bean>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>

Running integration tests with Spring boot (NoSuchBeanDefinitionException)

I am trying to sort out the following issue.
I've created a Spring Boot application which is also using Spring Data.
To do integration tests, I want to power up an H2 database.
I configured the test with #ContextConfiguration and referenced my applicationContext.xml file.
When I am running the tests out of the IDE (intelliJ) everything is fine, and the test is getting grean.
But as soon as I run the test on my build server or in the console with gradle, I get NoSuchBeanDefinitionException. It seems like the applicationContext is not considered at all...
Actually I have no clue anymore what to do..
My applicationContext-test.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:data="http://www.springframework.org/schema/data/jpa"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<context:component-scan base-package="de.company.project"/>
<bean class=
"org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
<bean class=
"org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"/>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${database.driverClassName}"/>
<property name="url" value="${database.url}"/>
<property name="username" value="${database.username}"/>
<property name="password" value="${database.password}"/>
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager"
id="transactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
id="entityManagerFactory">
<property name="persistenceUnitName" value="persistenceUnit"/>
<property name="dataSource" ref="dataSource"/>
<property name="persistenceXmlLocation" value="classpath:META-INF/persistence-
test.xml"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="org.hibernate.dialect.H2Dialect"/>
</bean>
</property>
</bean>
</beans>
My persistenc-test.xml:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="persistenceUnit"
transaction-type="RESOURCE_LOCAL">
<class>de.company.project.server.model.Entity</class>
<properties>
<property name="hibernate.hbm2ddl.auto" value="create-drop" />
<property name="hibernate.ejb.naming_strategy"
value="org.hibernate.cfg.ImprovedNamingStrategy" />
<property name="hibernate.connection.charSet" value="UTF-8" />
<property name="hibernate.default_schema" value="public" />
<property name="hibernate.show_sql" value="true" />
</properties>
</persistence-unit>
</persistence>
The database.properties just contains the defaults for an H2 database.
And last but not least my Testclass
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("classpath:*META-INF/applicationContext-test.xml")
public class EntityServiceTest {
#Test
public void doSomeStuff(){
}
.
.
}
I hope somebody has a clue what I am doing wrong?!
BR
Edit:
Missed to add the exception and the respository:
#Repository
public interface EntityRepository extends JpaRepository<Entity, Integer> {
}
Exception:
Caused by:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying
bean of type [de.company.project.server.dao.EntityRepository] found for dependency:
expected at least 1 bean which qualifies as autowire candidate for this dependency.
Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
I fixed it by adding TransactionalTestExecutionListener.class to my TestExecutionListeners.
I think the #Repository annotation should be on the implementation and not the interface. I assume you have this interface #Autowired somewhere else. Spring needs to know which concrete class should be used.
Also, the config file may not be found on the classpath with unit tests. Place the test context config in src/test/resources and change the configuration annotation to:
#ContextConfiguration(locations = "classpath:/applicationContext-test.xml")
See this answer (and others for the same question) for more info: https://stackoverflow.com/a/4377840/3851006

Is PersistenceAnnotationBeanPostProcessor of any use at all?

According to its JavaDoc, PersistenceAnnotationBeanPostProcessor seems to be responsible for injecting the EntityManager with the annotation #PersistenceContext. It appears to imply without this bean declared in the Spring application context xml, the #PersistenceContext annotation won't work.
However, based on my experiments, this is not the truth.
Persistence.xml
<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_1_0.xsd"
version="1.0">
<persistence-unit name="default" transaction-type="RESOURCE_LOCAL" />
</persistence>
Spring application context XML
<context:component-scan base-package="com.test.dao" />
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="persistenceUnitName" value="default"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true"/>
<property name="generateDdl" value="true"/>
<property name="databasePlatform" value="org.hibernate.dialect.DerbyDialect"/>
</bean>
</property>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.apache.derby.jdbc.ClientDriver"/>
<property name="url" value="jdbc:derby://localhost:1527/c:\derbydb\mydb"/>
<property name="username" value="APP"/>
<property name="password" value="APP"/>
</bean>
<tx:annotation-driven/>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<!--
<bean id="persistenceAnnotation" class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
-->
UserDaoImpl
#Repository("userDao")
public class UserDaoImpl implements UserDao {
#PersistenceContext
protected EntityManager entityManager;
#Transactional
public void save(User user) {
entityManager.persist(user);
}
}
Whether I comment or uncomment the persistenceAnnotation bean, the result is the same. It doesn't hurt to leave the bean around, but what's the use of this bean?
I am using Spring 3.0.5.
Could someone provide a scenario where taking out this bean will result in failure?
Also I am not fond of creating an empty persistence unit just to fool Spring. Luckily this problem has been addressed in Spring 3.1.0.
The PersistenceAnnotationBeanPostProcessor transparently activated by the <context:component-scan /> element. To be precise it's the <context:annotation-config /> element that activates the bean but this element in turn gets transparently activated by <context:component-scan />.
As Oliver Gierke mentioned, org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor is automatically loaded into App Context by Spring when using annotation based configuration. One of its duties is to search the proper entity EntityManagerFactory that would provide the EntityManager for you #PersistenceContext annotated properties.
If you have multiple EntityManagerFactory beans in you spring config/context and you have #PersistenceContext annotations without a unitName attribute (lets say you are using a framework that comes with such a bean, and you can't touch framework code), you may run into this exception: org.springframework.beans.factory.NoUniqueBeanDefinitionException.
I found this workaround in case you tun into this:
<bean id="org.springframework.context.annotation.internalPersistenceAnnotationProcessor"
class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" >
<property name="defaultPersistenceUnitName" value="entityManagerFactory"/>
</bean>
This would override the default PersistenceAnnotationBeanPostProcessor loaded by Spring with a new one with defaultPersistenceUnitName.

Categories