While developing a JPA-backed CXF web service for SMX4 (v
2011.01.0-fuse-00-00), I discovered some odd behaviour with respect to the
injection of a thread-bound EntityManager. I originally had service layer,
persistence unit and datasource in separate bundles, but the odd behaviour
occurs even when all layers exist in the same OSGi bundle. This behaviour
does NOT occur during unit testing. The problem is that the transaction is
created at the service layer:
@Service("messageService")
public class MessageServiceImpl implements MessageService {
@Autowired
private MessageDAO messageDAO;
@Override
@Transactional(propagation = Propagation.REQUIRED, readOnly = false)
public void save(Message message) {
messageDAO.save(message);
}
}
...and propagated at the persistence layer:
@Repository("messageDAO")
public class SpringJpaMessageDAO implements MessageDAO {
@PersistenceContext
private EntityManager em;
@Override
@Transactional(propagation = Propagation.MANDATORY, readOnly = false)
public void save(Message message) {
em.persist(message);
}
}
The call to persist() results in a NullPointerException for the
EntityManager. This is despite the fact that the logs clearly indicate
Spring has found an active transaction and a thread-bound EntityManager:
18:56:09,469 | DEBUG | xtenderThread-17 | JpaTransactionManager |
101 - org.springframework.transaction - 3.0.5.RELEASE | Creating new
transaction with name [org.example.service.MessageServiceImpl.save]:
PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
18:56:09,474 | DEBUG | xtenderThread-17 | JpaTransactionManager |
101 - org.springframework.transaction - 3.0.5.RELEASE | Opened new
EntityManager [org.hibernate.ejb.EntityManagerImpl@1241201a] for JPA
transaction
18:56:09,490 | DEBUG | xtenderThread-17 | JpaTransactionManager |
101 - org.springframework.transaction - 3.0.5.RELEASE | Exposing JPA
transaction as JDBC transaction
[org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@b6dcd37]
18:56:09,490 | TRACE | xtenderThread-17 | ransactionSynchronizationManager |
101 - org.springframework.transaction - 3.0.5.RELEASE | Bound value
[org.springframework.jdbc.datasource.ConnectionHolder@55bbdbbd] for key
[org.apache.commons.dbcp.BasicDataSource@7d22f244] to thread
[SpringOsgiExtenderThread-17]
18:56:09,490 | TRACE | xtenderThread-17 | ransactionSynchronizationManager |
101 - org.springframework.transaction - 3.0.5.RELEASE | Bound value
[org.springframework.orm.jpa.EntityManagerHolder@50e7a7f2] for key
[org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@18c32a5d]
to thread [SpringOsgiExtenderThread-17]
18:56:09,490 | TRACE | xtenderThread-17 | ransactionSynchronizationManager |
101 - org.springframework.transaction - 3.0.5.RELEASE | Initializing
transaction synchronization
18:56:09,490 | TRACE | xtenderThread-17 | TransactionInterceptor |
101 - org.springframework.transaction - 3.0.5.RELEASE | Getting transaction
for [org.example.service.MessageServiceImpl.save]
18:56:09,490 | DEBUG | xtenderThread-17 | tationTransactionAttributeSource |
101 - org.springframework.transaction - 3.0.5.RELEASE | Adding transactional
method 'save' with attribute: PROPAGATION_MANDATORY,ISOLATION_DEFAULT; ''
18:56:09,491 | TRACE | xtenderThread-17 | ransactionSynchronizationManager |
101 - org.springframework.transaction - 3.0.5.RELEASE | Retrieved value
[org.springframework.orm.jpa.EntityManagerHolder@50e7a7f2] for key
[org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@18c32a5d]
bound to thread [SpringOsgiExtenderThread-17]
18:56:09,491 | DEBUG | xtenderThread-17 | JpaTransactionManager |
101 - org.springframework.transaction - 3.0.5.RELEASE | Found thread-bound
EntityManager [org.hibernate.ejb.EntityManagerImpl@1241201a] for JPA
transaction
18:56:09,491 | TRACE | xtenderThread-17 | ransactionSynchronizationManager |
101 - org.springframework.transaction - 3.0.5.RELEASE | Retrieved value
[org.springframework.jdbc.datasource.ConnectionHolder@55bbdbbd] for key
[org.apache.commons.dbcp.BasicDataSource@7d22f244] bound to thread
[SpringOsgiExtenderThread-17]
18:56:09,491 | DEBUG | xtenderThread-17 | JpaTransactionManager |
101 - org.springframework.transaction - 3.0.5.RELEASE | Participating in
existing transaction
18:56:09,491 | TRACE | xtenderThread-17 | TransactionInterceptor |
101 - org.springframework.transaction - 3.0.5.RELEASE | Getting transaction
for [org.example.persist.SpringJpaMessageDAO.save]
18:56:09,491 | TRACE | xtenderThread-17 | TransactionInterceptor |
101 - org.springframework.transaction - 3.0.5.RELEASE | Completing
transaction for [org.example.persist.SpringJpaMessageDAO.save] after
exception: java.lang.NullPointerException
18:56:09,491 | TRACE | xtenderThread-17 | RuleBasedTransactionAttribute |
101 - org.springframework.transaction - 3.0.5.RELEASE | Applying rules to
determine whether transaction should rollback on
java.lang.NullPointerException
18:56:09,491 | TRACE | xtenderThread-17 | RuleBasedTransactionAttribute |
101 - org.springframework.transaction - 3.0.5.RELEASE | Winning rollback
rule is: null
18:56:09,491 | TRACE | xtenderThread-17 | RuleBasedTransactionAttribute |
101 - org.springframework.transaction - 3.0.5.RELEASE | No relevant rollback
rule found: applying default rules
18:56:09,491 | DEBUG | xtenderThread-17 | JpaTransactionManager |
101 - org.springframework.transaction - 3.0.5.RELEASE | Participating
transaction failed - marking existing transaction as rollback-only
18:56:09,491 | DEBUG | xtenderThread-17 | JpaTransactionManager |
101 - org.springframework.transaction - 3.0.5.RELEASE | Setting JPA
transaction on EntityManager [org.hibernate.ejb.EntityManagerImpl@1241201a]
rollback-only
18:56:09,491 | TRACE | xtenderThread-17 | TransactionInterceptor |
101 - org.springframework.transaction - 3.0.5.RELEASE | Completing
transaction for [org.example.service.MessageServiceImpl.save] after
exception: java.lang.NullPointerException
18:56:09,491 | TRACE | xtenderThread-17 | RuleBasedTransactionAttribute |
101 - org.springframework.transaction - 3.0.5.RELEASE | Applying rules to
determine whether transaction should rollback on
java.lang.NullPointerException
18:56:09,491 | TRACE | xtenderThread-17 | RuleBasedTransactionAttribute |
101 - org.springframework.transaction - 3.0.5.RELEASE | Winning rollback
rule is: null
18:56:09,491 | TRACE | xtenderThread-17 | RuleBasedTransactionAttribute |
101 - org.springframework.transaction - 3.0.5.RELEASE | No relevant rollback
rule found: applying default rules
18:56:09,491 | DEBUG | xtenderThread-17 | JpaTransactionManager |
101 - org.springframework.transaction - 3.0.5.RELEASE | Initiating
transaction rollback
18:56:09,491 | DEBUG | xtenderThread-17 | JpaTransactionManager |
101 - org.springframework.transaction - 3.0.5.RELEASE | Rolling back JPA
transaction on EntityManager [org.hibernate.ejb.EntityManagerImpl@1241201a]
18:56:09,492 | TRACE | xtenderThread-17 | ransactionSynchronizationManager |
101 - org.springframework.transaction - 3.0.5.RELEASE | Clearing transaction
synchronization
18:56:09,492 | TRACE | xtenderThread-17 | ransactionSynchronizationManager |
101 - org.springframework.transaction - 3.0.5.RELEASE | Removed value
[org.springframework.orm.jpa.EntityManagerHolder@50e7a7f2] for key
[org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@18c32a5d]
from thread [SpringOsgiExtenderThread-17]
18:56:09,492 | TRACE | xtenderThread-17 | ransactionSynchronizationManager |
101 - org.springframework.transaction - 3.0.5.RELEASE | Removed value
[org.springframework.jdbc.datasource.ConnectionHolder@55bbdbbd] for key
[org.apache.commons.dbcp.BasicDataSource@7d22f244] from thread
[SpringOsgiExtenderThread-17]
18:56:09,492 | DEBUG | xtenderThread-17 | JpaTransactionManager |
101 - org.springframework.transaction - 3.0.5.RELEASE | Closing JPA
EntityManager [org.hibernate.ejb.EntityManagerImpl@1241201a] after
transaction
...
Caused by: java.lang.NullPointerException
at
org.example.persist.SpringJpaMessageDAO.save(SpringJpaMessageDAO.java:22)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native
Method)[:1.6.0_26]
at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)[:1.6.0_26]
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)[:1.6.0_26]
at java.lang.reflect.Method.invoke(Method.java:597)[:1.6.0_26]
at
org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:309)[87:org.springframework.aop:3.0.5.RELEASE]
at
org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)[87:org.springframework.aop:3.0.5.RELEASE]
at
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)[87:org.springframework.aop:3.0.5.RELEASE]
at
org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)[101:org.springframework.transaction:3.0.5.RELEASE]
at
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)[87:org.springframework.aop:3.0.5.RELEASE]
at
org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)[87:org.springframework.aop:3.0.5.RELEASE]
at $Proxy172.save(Unknown Source)
at
org.example.service.MessageServiceImpl.save(MessageServiceImpl.java:36)
I have a maven sample project that exhibits the behaviour, available on
request.
--
View this message in context:
http://servicemix.396122.n5.nabble.com/JPA-EntityManager-not-properly-injected-for-annotation-based-config-tp5014530p5014530.html
Sent from the ServiceMix - User mailing list archive at Nabble.com.