You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When there is a prototype bean with a field annotated with @Autowired whose value is a prototype bean created in dependence of its injection point it seams that the the injection point isn't propagated.
Test setup:
public class MyBeanImpl implements MyBean {
@Autowired
private Logger logger;
@PostConstruct
public void init() {
logger.info("Hello World");
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class MyTest {
@Configuration
static class TestConfiguration {
@Bean
@Scope(SCOPE_PROTOTYPE)
public Logger createLogger(InjectionPoint injectionPoint) {
return LogManager.getLogger(injectionPoint.getMember().getDeclaringClass());
}
@Bean
@Scope(SCOPE_PROTOTYPE)
public MyBean createMyBean() {
return new MyBeanImpl();
}
}
@Autowired
private MyBean beanA;
@Autowired
private MyBean beanB;
@Test
public void test() {
}
public static void main(String[] args) {
try (AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(TestConfiguration.class)) {
ctx.getBean(MyBean.class);
ctx.getBean(MyBean.class);
}
}
}
If I execute the test then I get the following log:
16:36:53.997 [main] INFO org.springframework.test.context.support.AbstractContextLoader - Could not detect default resource locations for test class [test.MyTest]: no resource found for suffixes {-context.xml}.
16:36:54.092 [main] INFO org.springframework.test.context.support.AbstractDelegatingSmartContextLoader - AnnotationConfigContextLoader detected default configuration classes for context configuration [ContextConfigurationAttributes@255b53dc declaringClass = 'test.MyTest', classes = '{class test.MyTest$TestConfiguration}', locations = '{}', inheritLocations = true, initializers = '{}', inheritInitializers = true, name = [null], contextLoaderClass = 'org.springframework.test.context.ContextLoader'].
16:36:54.105 [main] INFO org.springframework.test.context.support.DefaultTestContextBootstrapper - Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener]
16:36:54.109 [main] INFO org.springframework.test.context.support.DefaultTestContextBootstrapper - Could not instantiate TestExecutionListener [org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener]. Specify custom listener classes or make the default listener classes (and their required dependencies) available. Offending class: [org/springframework/transaction/interceptor/TransactionAttribute]
16:36:54.110 [main] INFO org.springframework.test.context.support.DefaultTestContextBootstrapper - Could not instantiate TestExecutionListener [org.springframework.test.context.web.ServletTestExecutionListener]. Specify custom listener classes or make the default listener classes (and their required dependencies) available. Offending class: [javax/servlet/ServletContext]
16:36:54.112 [main] INFO org.springframework.test.context.support.DefaultTestContextBootstrapper - Could not instantiate TestExecutionListener [org.springframework.test.context.transaction.TransactionalTestExecutionListener]. Specify custom listener classes or make the default listener classes (and their required dependencies) available. Offending class: [org/springframework/transaction/interceptor/TransactionAttributeSource]
16:36:54.112 [main] INFO org.springframework.test.context.support.DefaultTestContextBootstrapper - Using TestExecutionListeners: [org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener@6295d394, org.springframework.test.context.support.DependencyInjectionTestExecutionListener@475e586c, org.springframework.test.context.support.DirtiesContextTestExecutionListener@657c8ad9]16:36:54.302 [main] INFO org.springframework.context.support.GenericApplicationContext - Refreshing org.springframework.context.support.GenericApplicationContext@27ae2fd0: startup date [Sat Jun 25 16:36:54 CEST 2016]; root of context hierarchy
16:36:54.757 [main] INFO test.MyBeanImpl - Hello World
16:36:54.758 [main] INFO test.MyTest - Hello World
16:36:54.764 [Thread-1] INFO org.springframework.context.support.GenericApplicationContext - Closing org.springframework.context.support.GenericApplicationContext@27ae2fd0: startup date [Sat Jun 25 16:36:54 CEST 2016]; root of context hierarchy
The lines 16:36:54.757 and 16:36:54.758 in the log show that the InjectionPoint of the Logger field differs, because the injection point's member declaring class is used to instantiate the logger. I would expect that they don't differ because both times the same bean is instantiated.
After a closer look I recognized that the second logger is instantiated for the test class MyTest, so I assume that the injection point isn't populated recursively. To prove my assumption I created the method MyTest#main() where I setup an ApplicationContext by hand. When I execute this method I get the following log:
16:56:43.372 [main] INFO org.springframework.context.annotation.AnnotationConfigApplicationContext - Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@436e852b: startup date [Sat Jun 25 16:56:43 CEST 2016]; root of context hierarchy
16:56:44.071 [main] INFO test.MyBeanImpl - Hello World
16:56:44.077 [main] INFO org.springframework.context.annotation.AnnotationConfigApplicationContext - Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@436e852b: startup date [Sat Jun 25 16:56:43 CEST 2016]; root of context hierarchy
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'createMyBean': Injection of autowired dependencies failed; nested exception is java.lang.IllegalStateException: No current InjectionPoint available for method 'createLogger' parameter 0
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:356)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:325)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:220)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:352)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:333)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1088)
at test.MyTest.main(MyTest.java:50)
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 com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Caused by: java.lang.IllegalStateException: No current InjectionPoint available for method 'createLogger' parameter 0
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:830)
at org.springframework.beans.factory.support.ConstructorResolver.resolvePreparedArguments(ConstructorResolver.java:784)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:415)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1123)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1018)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:325)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.resolvedCachedArgument(AutowiredAnnotationBeanPostProcessor.java:533)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.access$200(AutowiredAnnotationBeanPostProcessor.java:118)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:562)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:350)
... 14 more
This log confirmed my assumption from above, because now there isn't a parent injection point and the thrown error state that there isn't an current injection point at all. I guess the that the method AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject must be fixed to populate the injection point of its field via ConstructorResolver#setCurrentInjectionPoint().
I have attached a maven project so that you are able to reproduce the observed behavior.
This was caused by AutowiredAnnotationBeanPostProcessor's optimization for pre-resolved target bean names: We went with a straight getBean call then which does not expose InjectionPoint metadata for such repeated calls. I've replaced this with a somewhat fancier resolveShortcut mechanism on DependencyDescriptor itself, called during the regular resolveDependency algorithm within the factory's {{InjectionPoint} exposure.
This will be available in the upcoming 4.3.1.BUILD-SNAPSHOT. Feel free to give it an early try...
Uh oh!
There was an error while loading. Please reload this page.
Sebastian Staack opened SPR-14400 and commented
When there is a prototype bean with a field annotated with
@Autowired
whose value is a prototype bean created in dependence of its injection point it seams that the the injection point isn't propagated.Test setup:
If I execute the test then I get the following log:
The lines 16:36:54.757 and 16:36:54.758 in the log show that the InjectionPoint of the Logger field differs, because the injection point's member declaring class is used to instantiate the logger. I would expect that they don't differ because both times the same bean is instantiated.
After a closer look I recognized that the second logger is instantiated for the test class MyTest, so I assume that the injection point isn't populated recursively. To prove my assumption I created the method
MyTest#main()
where I setup anApplicationContext
by hand. When I execute this method I get the following log:This log confirmed my assumption from above, because now there isn't a parent injection point and the thrown error state that there isn't an current injection point at all. I guess the that the method
AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject
must be fixed to populate the injection point of its field viaConstructorResolver#setCurrentInjectionPoint()
.I have attached a maven project so that you are able to reproduce the observed behavior.
Affects: 4.3 GA
Attachments:
Issue Links:
@Bean
methodReferenced from: commits e15f7ef
The text was updated successfully, but these errors were encountered: