TransactionRequiredException while install/uninstall add-on

Hello everyone,

We’re getting an Atlassian exception when installing or uninstalling our add-on. We can’t ignore it or handle it, but some clients claim persistent problems with it.

javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread - cannot reliably process 'merge' call
 at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:298)
 at com.sun.proxy.$Proxy141.merge(Unknown Source)
 at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:557)
 at sun.reflect.GeneratedMethodAccessor319.invoke(Unknown Source)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 at java.lang.reflect.Method.invoke(Method.java:498)
 at org.springframework.data.repository.core.support.ImplementationInvocationMetadata.invoke(ImplementationInvocationMetadata.java:72)

Thanks in advance,
Nataliya Timoshina
PM at Alpha Serve

Hi @NataliyaTimoshina, that is not an Atlassian exception. I would think it is related to how you use database transactions in your app. Have you been able to sort this out?

Hi @epehrson ,

the exception is sent from com.atlassian.connect.spring.internal.lifecycle.LifecycleController.uninstalled(LifecycleController.java:154), I’m adding a full stack trace below:

19-08-2021 12:56:09.965 [http-nio-8080-exec-7] ERROR c.a.c.c.c.ExceptionController.buildResponseEntity - No EntityManager with actual transaction available for current thread - cannot reliably process 'merge' call
javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread - cannot reliably process 'merge' call
	at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:295)
	at com.sun.proxy.$Proxy141.merge(Unknown Source)
	at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:560)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.data.repository.core.support.RepositoryMethodInvoker$RepositoryFragmentMethodInvoker.lambda$new$0(RepositoryMethodInvoker.java:289)
	at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:137)
	at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:121)
	at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:524)
	at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:285)
	at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:531)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:156)
	at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:131)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:174)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215)
	at com.sun.proxy.$Proxy143.save(Unknown Source)
	at com.atlassian.connect.spring.internal.lifecycle.LifecycleController.uninstalled(LifecycleController.java:154)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)

@NataliyaTimoshina, I see. Looking at spring-data-jpa/SimpleJpaRepository.java at main · spring-projects/spring-data-jpa · GitHub and spring-framework/SharedEntityManagerCreator.java at main · spring-projects/spring-framework · GitHub sheds some light on how this works, but it’s not clear to me why you are seeing this error and we don’t see it in our test suite, where we also use Spring Data JPA, and of course have tests for both reinstall and uninstall.

Since noone else has reported this issue, I think there is something different about your app configuration that causes this to happen. Could you try to reproduce this issue in a test case and submit a pull request to atlassian-connect-spring-boot with it? Or perhaps reproduce it manually with a minimal sample project?

Hello @epehrson , we’ve created a sample application and checked that it gives the same exception:

https://bitbucket.org/Dkvashenko/test/src/master/

Best regards,
Nataliya

Thanks, @NataliyaTimoshina, that is great. I have raised this as ACSPRING-138 and will escalate it internally.

Could you please edit the issue and add steps to reproduce the error? Does it happen on first install, or is there a specific sequence of steps required?

I am also a bit confused about AtlassianHostRepositoryConfiguration and AtlassianHostDAO in your sample app. Without those, the error doesn’t occur? If so, does the error still occur if you use Spring’s repository scanning instead? Or, if you used RepositoryFactorySupport#getRepository to create AtlassianHostRepository as well?