Sunday, September 12, 2010

@Transactional autowiring problem



Given this bean1 that contains bean2
Bean1:
@Component
public class ServiceImpl implements Service {
 
    @Autowired
    private DelegateService m_delegate;
...
}
 
Breaks when using @Transactional on the delegate component:
 
@Component
@Transactional
public class DelegateService implements Service {
...
}
 
 
With this exception:
 
java.lang.IllegalStateException: Failed to load ApplicationContext
       at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:201)
       at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:109)
       at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75)
       at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:255)
       at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:111)
       at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.invokeTestMethod(SpringJUnit4ClassRunner.java:148)
       at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:51)
       at org.junit.internal.runners.JUnit4ClassRunner$1.run(JUnit4ClassRunner.java:44)
       at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:27)
       at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:37)
       at org.junit.internal.runners.JUnit4ClassRunner.run(JUnit4ClassRunner.java:42)
       at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:97)
       at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46)
       at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
       at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
       at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
       at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
       at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'ServiceImpl': Autowiring of fields failed; nested exception is Could not autowire field: private com.service.DelegateService com.service.ServiceImpl.m_Service; nested exception is java.lang.IllegalArgumentException: Can not set com.service.DelegateService field com.service.ServiceImpl.m_delegate to $Proxy32
       at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessAfterInstantiation(AutowiredAnnotationBeanPostProcessor.java:243)
       at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:959)
       at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:472)
       at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:409)
       at java.security.AccessController.doPrivileged(Native Method)
       at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:380)
       at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:264)
       at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
       at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:261)
       at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185)
       at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164)
       at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:429)
       at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:728)
       at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:380)
       at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:84)
       at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:42)
       at org.springframework.test.context.TestContext.loadApplicationContext(TestContext.java:173)
       at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:197)
       ... 17 more
 
 
Same thing happens if @Transactional is applied at the method level instead of class level.


Solution is to @Autowire the delegate with resource name.