From 547b9638dc851e8b25bf719abc30acc1a49b3ff6 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Fri, 9 Dec 2016 23:09:10 +0100 Subject: [PATCH] Collection injection may refer back to factory methods on same bean again Issue: SPR-14996 --- .../support/DefaultListableBeanFactory.java | 36 ++++++++++--------- .../ConfigurationClassPostProcessorTests.java | 22 ++++++++++++ 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java index 1e763db2c7c..ba96a380bc8 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java @@ -1137,7 +1137,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto if (type.isArray()) { Class componentType = type.getComponentType(); Map matchingBeans = findAutowireCandidates(beanName, componentType, - new MultiElementDependencyDescriptor(descriptor)); + new MultiElementDescriptor(descriptor)); if (matchingBeans.isEmpty()) { return null; } @@ -1157,7 +1157,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto return null; } Map matchingBeans = findAutowireCandidates(beanName, elementType, - new MultiElementDependencyDescriptor(descriptor)); + new MultiElementDescriptor(descriptor)); if (matchingBeans.isEmpty()) { return null; } @@ -1181,7 +1181,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto return null; } Map matchingBeans = findAutowireCandidates(beanName, valueType, - new MultiElementDependencyDescriptor(descriptor)); + new MultiElementDescriptor(descriptor)); if (matchingBeans.isEmpty()) { return null; } @@ -1248,25 +1248,27 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto } } } - for (String candidateName : candidateNames) { - if (!isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, descriptor)) { - addCandidateEntry(result, candidateName, descriptor, requiredType); + for (String candidate : candidateNames) { + if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) { + addCandidateEntry(result, candidate, descriptor, requiredType); } } if (result.isEmpty() && !indicatesMultipleBeans(requiredType)) { // Consider fallback matches if the first pass failed to find anything... DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch(); - for (String candidateName : candidateNames) { - if (!isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, fallbackDescriptor)) { - addCandidateEntry(result, candidateName, descriptor, requiredType); + for (String candidate : candidateNames) { + if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor)) { + addCandidateEntry(result, candidate, descriptor, requiredType); } } - if (result.isEmpty() && !(descriptor instanceof MultiElementDependencyDescriptor)) { + if (result.isEmpty()) { // Consider self references as a final pass... - // but not as collection elements, just for direct dependency declarations. - for (String candidateName : candidateNames) { - if (isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, fallbackDescriptor)) { - addCandidateEntry(result, candidateName, descriptor, requiredType); + // but in the case of a dependency collection, not the very same bean itself. + for (String candidate : candidateNames) { + if (isSelfReference(beanName, candidate) && + (!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) && + isAutowireCandidate(candidate, fallbackDescriptor)) { + addCandidateEntry(result, candidate, descriptor, requiredType); } } } @@ -1281,7 +1283,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto private void addCandidateEntry(Map candidates, String candidateName, DependencyDescriptor descriptor, Class requiredType) { - if (descriptor instanceof MultiElementDependencyDescriptor || containsSingleton(candidateName)) { + if (descriptor instanceof MultiElementDescriptor || containsSingleton(candidateName)) { candidates.put(candidateName, descriptor.resolveCandidate(candidateName, requiredType, this)); } else { @@ -1730,9 +1732,9 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto } - private static class MultiElementDependencyDescriptor extends NestedDependencyDescriptor { + private static class MultiElementDescriptor extends NestedDependencyDescriptor { - public MultiElementDependencyDescriptor(DependencyDescriptor original) { + public MultiElementDescriptor(DependencyDescriptor original) { super(original); } } diff --git a/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java b/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java index 7e44baba65c..50dac8e5066 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java @@ -20,6 +20,7 @@ import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import java.util.List; import javax.annotation.PostConstruct; import org.junit.Before; @@ -615,6 +616,15 @@ public class ConfigurationClassPostProcessorTests { assertSame(ctx.getBean(BarImpl.class), ctx.getBean(FooImpl.class).bar); } + @Test + public void testCollectionInjectionFromSameConfigurationClass() { + ApplicationContext ctx = new AnnotationConfigApplicationContext(CollectionInjectionConfiguration.class); + CollectionInjectionConfiguration bean = ctx.getBean(CollectionInjectionConfiguration.class); + assertNotNull(bean.testBeans); + assertEquals(1, bean.testBeans.size()); + assertSame(ctx.getBean(TestBean.class), bean.testBeans.get(0)); + } + // ------------------------------------------------------------------------- @@ -1253,4 +1263,16 @@ public class ConfigurationClassPostProcessorTests { } } + @Configuration + static class CollectionInjectionConfiguration { + + @Autowired(required = false) + public List testBeans; + + @Bean + public TestBean thing() { + return new TestBean(); + } + } + }