Hello, I have a complex auto wiring scenario that seems to be only happening in production.
Affected versions:
- Spring Core 5.3.27
- Spring Batch 4.3.8
- Spring ORM 5.3.27
- Hibernate 5.4.33
- Note I am not using Spring Boot at all.
In particular, I have a transactionManager
bean that is a HibernateTransactionManager
and another transactionManagerTarget
bean that is of type DataSourceTransactionManager
. The doGetTransaction()
method is failing at runtime because of a ClassCastException.
While I am not able to reproduce the issue to send as a sample project (I tried), I wanted to offer this small rewrite. It is 100% backwards compatible and simply routes into the else
block instead of throwing a ClassCastException at runtime. I would greatly appreciate if it could be considered in an upcoming release!
instanceof
check automatically handles the!= null
case- rewriting cast to avoid potential ClassCastException scenarios
- specifically avoiding runtime
java.lang.ClassCastException: org.springframework.orm.jpa.EntityManagerHolder cannot be cast to org.springframework.orm.hibernate5.SessionHolder
Lastly, here is the original stack trace. Thank you!
Caused by: java.lang.ClassCastException: org.springframework.orm.jpa.EntityManagerHolder cannot be cast to org.springframework.orm.hibernate5.SessionHolder
at org.springframework.orm.hibernate5.HibernateTransactionManager.doGetTransaction(HibernateTransactionManager.java:425)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:347)
at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:595)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:382)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:241)
at com.sun.proxy.$Proxy74.updateExecutionContext(Unknown Source)~[?:?]
at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:452)
... 14 more
Comment From: snicoll
Unfortunately, that would be hiding the actual issue rather than fixing it. Without a test that demonstrates why this is legit to be lenient like that, this PR isn't actionable. And we wouldn't make such a change in 5.3.x at this point either.
Chatting with @jhoeller, it looks like you have a case with a nested transaction and incompatible resource management, which must be fixed in your application. Perhaps the outer transaction is using JPATransactionManager
that ends up delegating to an inner transaction using HibernateTransactionManager
, pointing to the same Hibernate SessionFactory
instance?
Comment From: NaanProphet
Hi! Thanks for your reply. No problem, it sense that you need a true RCA to consider the PR, so I will keep trying to recreate a test to present.
I appreciate the tip about the nested transaction scenario - I will look into that more closely!