I'm trying to setup entity manager with Spring 4 and I always get NullPointerException when I try to inject EntityManager with #PersistenceContext annotation.
I have Maven web application. Here's my applicationContext.xml configuration
<bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="EcommercePU">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan">
<list>
<value>com.mysite.ecommerceapp.domain</value>
<value>com.mysite.ecommerceapp.domain.*</value>
<value>com.mysite.ecommerceapp.domain.*.*</value>
<value>com.mysite.ecommerceapp.domain.*.*.*</value>
</list>
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true"/>
</bean>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">create-drop</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQL9Dialect</prop>
</props>
</property>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.postgresql.Driver" />
<property name="url" value="jdbc:postgresql://localhost:5432/ecommercedb" />
<property name="username" value="postgres" />
<property name="password" value="test" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="myEmf" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="persistenceExceptionTranslationPostProcessor"
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
applicationContext.xml is located under WEB-INF folder. Because I use NetBeans 8 I added Spring Framework support to my project from project properties -> Frameworks. I'm using EntityManager injection with file called GenericDaoImpl and here's it's code:
public abstract class GenericDaoImpl<E extends EntityClass> implements GenericDao<E> {
private Class<E> entityClass;
#PersistenceContext()
private EntityManager entityManager;
//Constructor
public GenericDaoImpl(final Class<E> entityClass) {
this.entityClass = entityClass;
}
//Getters and Setters
public Class<E> getEntityClass() {
return entityClass;
}
public void setEntityClass(final Class<E> entityClass) {
this.entityClass = entityClass;
}
public EntityManager getEntityManager() {
return entityManager;
}
public void setEntityManager(final EntityManager entityManager) {
this.entityManager = entityManager;
}
public void checkEntityManager() {
System.out.println("em: " + this.entityManager);
}
}
I have one test file where I simply print entity manager with checkEntityManager() method. Whenever I run it I always get null value for EntityManager. What could be wrong? My biggest doubt is that my applicationContext.xml is in wrong place or it is not used anywhere and thus it can't find configuration properties in applicationContext. I have tested moving applicationContext.xml file to resources folder but it didn't helped either. Other questions that I also have are following:
Do I need to have persistence.xml? Since I use Spring 4 with packagesToScan feature I heard that persistence.xml is not required but I'm not sure.
Is it wise to use hibernate to take care only basic entities cruds and other dao queries with JdbcTemplate?
All help would be appreciated.
I finally solved the problem and there were lots of things that has to be done.
When I tested my Entity Manager through JUnit tests I got NullPointerException and reason was the configuration file was incorrect folder.
applicationContext.xml was properly setup except there was a small problem that messed the whole file and that was <property name="persistenceUnitName" value="EcommercePU">. Because I didn't had such persistence unit file in whole project it couldn't find it. When you add that property it doesn't mean that you have created a spring configuration file that has such persistence unit name. It simply means that if you want to provide persistence configurations to your LocalContainerEntityManagerFactory you would refer with that name to your persistence unit. This is not required in Spring 4.
applicationContext.xml had to be moved from WEB-INF to resources folder.
When you would run JUnit tests you should use #Autowired annotation to annotate DAO's.
Dao implementation classes should have #Repository annotation.
#Transactional annotation is required at least for CRUD methods if you are going to use. You can also annotate whole class. If you don't add #Transactional annotation EntityManager wouldn't execute persist, remove, update, find and other methods properly. Remember this is required if you are using Spring configurations.
Related
I'm trying to open multiple transactions​ on a method using #Transactional by Spring framework
And for some reason it's throws java.lang.IllegalStateException : Transaction already active
My method
#Transactional
Public void foo(Entity e){
entityManager.merge(e);
entityManager.getTransaction().begin();
entityManager.getTransaction().commit();
}
Any idea how to open multiple transaction without getting that error?
I think you may be confusing what the Spring #Transactional annotation means. When you use that annotation you're asking Spring to enrich your method invocation with transaction semantics.
You may want to take a look at the TransactionAspectSupport class, more specifically the method invokeWithinTransaction which is the place where all the magic happens for your transactional methods.
You will see there that before your code is invoked, a new transaction is created, then your code is executed, and after that, either a commit or rollback happens. In other words, Spring's aspect controls the transaction for you.
All these magic needs some configuration for it to happen: you need to make sure that Spring finds your #Transactional methods and enrich them. To do so you need to add a piece of configuration:
<tx:annotation-driven/>
And of course you need to define a transaction manager that can be used by your transactional methods. It seems you're using JPA so a JpaTransactionManager makes sense in this case:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="POSTGRESQL"/>
<property name="showSql" value="true"/>
</bean>
</property>
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect">
<property name="prepareConnection" value="true"/>
</bean>
</property>
<property name="persistenceUnitName" value="test-api"/>
<property name="packagesToScan">
<list>
<value>com.company.humanresources</value>
</list>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<constructor-arg name="emf" ref="entityManagerFactory"/>
</bean>
Finally, if you want to gain access to the entity manager being used by your current transaction, you can do something like:
#PersistenceUnit(unitName = "test-api")
EntityManagerFactory emf;
#Transactional
public Department addDepartment(String name) {
EntityManager em = EntityManagerFactoryUtils.getTransactionalEntityManager(emf);
Department department = new Department();
department.setName(name);
em.persist(department);
return department;
});
Once more, Spring will control the transaction semantics around your transactional method. You must also take into account that the default Spring behavior only works with public methods.
I have such simple class for JUnit test:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:/mysql-datasource-context.xml"})
public class EmployeeDAOTest {
#Autowired
EmployeeDao employeeDao;
#Test
public void findAllTest() {
assertTrue(employeeDao.findByName("noname").size() == 0);
}
}
The content of the mysql-datasource-context.xml looks like this:
<context:component-scan base-package="my.packages.*"/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/project"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan" value="my.packages.entity"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
<prop key="show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
Now the test runs with no problem for my mysql database.
The point is that I also have a postgres database and I need every test run both for the mysql and postgres databases.
The only solution that comes to my mind is creating one more test class with exactly the same tests but annotate it as
#ContextConfiguration(locations = {"classpath:/postgres -datasource-context.xml"})
and create one more datasource context file for it. Unfortunately this way doesn't look like a good solution.
Is there a better way to solve my problem?
I think that the simplest solution is to keep a test class as the base one:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:/mysql-datasource-context.xml"})
public class EmployeeDAOTest {
#Autowired
EmployeeDao employeeDao;
#Test
public void findAllTest() {
assertTrue(employeeDao.findByName("noname").size() == 0);
}
}
and then creating one empty subclass for postgres with its own configuration:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:/postgres-datasource-context.xml"}, inheritLocations=false)
public class EmployeeDAOTestPostgres extends EmployeeDAOTest {
}
As other suggested you can alter your Spring config files in order to have only one; you can for example put the datasource in a separate context and import it or use a profile (see here for an example)
At a glance is the spring multiple data source configure, actually you can get a lot posts for this via google or quickly search it in stackoverflow
Example:
Spring Boot Multiple Datasource
Another solution I can image is using the spring profile.
I always find it's best to have a top level app context file which includes other files:
appcontext-root.xml
<beans>
<import resource="appcontext-services.xml"/>
<import resource="appcontext-db.xml"/>
</beans>
Then your application can run the context-root.xml, but your tests can test one (or more) of the lower level files.
If you want a swappable back end, you might consider using a PropertyPlaceHolderConfigurer.
eg:
<import resource="appcontext-db-${vendor}.xml"/>
And have a appcontext-db-mysql.xml, appcontext-db-postgres.xml along with System.setProperty("vendor", "mysql")
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.
My service makes use of a generic DAO (which explicitly uses Hibernate session factory). I have spent some time before I discovered this error
org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
I annotated my service and all works perfectly. Now I want to use context path scanning, and remove this line from my configuration:
<bean id="societaService" class="it.trew.prove.services.SocietaService" />
So.... here's my final version:
#Service
#Transactional(readOnly = true)
public class SocietaService {
private Dao societaDao;
#Autowired
public void setSocietaDao(Dao societaDao) {
this.societaDao = societaDao;
}
public void salvaSocieta(Societa s) {
societaDao.save(s);
}
public List<Societa> listAll() {
return societaDao.getAll(Societa.class);
}
public void deleteById(Long id) {
societaDao.delete(getSocieta(id));
}
public Societa getSocieta(String id) {
return getSocieta(Long.parseLong(id));
}
public Societa getSocieta(Long id) {
return societaDao.get(Societa.class, id);
}
}
Adding #Service annotation makes my app give the awful hibernate error above. Why?
Removing #Service and configuring the service bean via xml = it works. WHY??
In addition:
does transactional annotating my service class makes all its methods to be executing in a transaction?
EDIT
Here's my context xml:
<context:annotation-config />
<context:component-scan base-package="it.trew.prove" />
<!-- Hibernate -->
<bean id="myDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.google.appengine.api.rdbms.AppEngineDriver" />
<property name="url" value="jdbc:google:rdbms://xxx:xxx/xxx" />
</bean>
<bean id="mySessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="myDataSource" />
<property name="annotatedClasses">
<list>
<value>it.trew.prove.model.beans.Scadenza</value>
<value>it.trew.prove.model.beans.Fornitore</value>
<value>it.trew.prove.model.beans.Societa</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
<!-- <prop key="hibernate.hbm2ddl.import_files">/setup.sql</prop> -->
</props>
</property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="mySessionFactory" />
</bean>
Did you enabled annotations ?
<context:annotation-config />
and
<context:component-scan base-package="org.example"/>
this will enable annotations like #Service, #Component and #Repository
First of all, you need to tell spring to enable Transactional annotation with something like that:
<tx:annotation-driven transaction-manager="transactionManager" />
Second, if you use #Transactional at class level, any call to a method of your Service will be transactional. Whether it starts a transaction or not depends on the "propagation" attribute. The default is start one if none started in this session (Propagation.REQUIRED). If you use #Transactional only at class level, all of your methods will inherit its attributes, i.e., if you set "readOnly = true", all of yours methods will be read only, thus, updates/saves/delete won't work. I would recommend you to read more the Spring Transaction Management Doc
I understand that this is a very long question, but i wanted to ask everything because i'm
stuck with these things for more than 2 weeks and i'm in a situation to solve this within
this week. Please guide me in this matter.
I'm Using EclipseLink jpa version 2, Spring 3, jdk6, MySQL5 and tomcat7.
I have configured the following in each of my DAO classes.
#PersistenceContext
private EntityManager em;
I have the following in my Spring xml:
<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">
<property name="url" value="jdbc:mysql://localhost:3306/xxxxx"/>
<property name="username" value="xxxx"/>
<property name="password" value="xxxx"/>
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
</bean>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
<property name="jpaDialect" ref="jpaDialect"/>
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
<property name="jpaDialect" ref="jpaDialect"/>
</bean>
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter" >
<property name="showSql" value="true"/>
<property name="generateDdl" value="true" />
</bean>
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect"/>
From Persistence.xml:
<persistence-unit name="xxxxx" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<-- class mappings -->
</persistence-unit>
I've got few confusion about what i have done:
Is the EntityManager injected by Spring? (I understand that #PersistenceContext is a
J2EE annotation, so wondering whether it is injected without Spring's contribution).
As i have already mentioned, i have injected EntityManager in all the DAO classes. Is
this a good practice? or should i make it Singleton by having a separate class like
PersistenceManager, which has EntityManager attribute wired, and have
getEntityManager() method?
As you can see above, i have configured Spring transactions. But when i do CRUD
operations continuously for 2-3 times, application gets stuck and fails with EclipseLink
exception saying unable to get lock, timeout etc. Am i doing anything wrong here or
missing any transaction configurations??
With the above configurations, i can only use #Transactional annotation with default
values which are PROPAGATION_REQUIRED,ISOLATION_DEFAULT. If i change these for any other
values, such as #Transactional(PROPAGATION_REQUIRED,ISOLATION_SERIALIZABLE) etc,
application throws exception as Custom isolation levels are not supported. Again, am
i missing any configurations?
Thanks.
Yes, spring recognizes the #PersistenceContext annotation and injects the entity manager
Spring takes care of that - it injects the same EntityManager instance in all DAOs. In fact, it injects a proxy so that each request uses a different entity manager.
Normally everything should run fine. You need <tx:annotation-driven /> in order to use #Transactional
JPA only supports the default isolation level. You can work this around by customizing the spring jpa dialect, but there's nothing built-in. The way to go is extend XJpaDialect (in your case X=EclipseLink), override the beingTransaction, obtain the Connection (in an eclipse-link specific way), set the desired isolation level (accessible through the transaction definition), and configure this as a property of your LocalContainerEntityManagerFactoryBean:
<property name="jpaDialect">
<bean class="com.foo.util.persistence.EclipseLinkExtendedJpaDialect" />
</property>