Collection injection may refer back to factory methods on same bean again
Issue: SPR-14996
This commit is contained in:
@@ -1137,7 +1137,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
|||||||
if (type.isArray()) {
|
if (type.isArray()) {
|
||||||
Class<?> componentType = type.getComponentType();
|
Class<?> componentType = type.getComponentType();
|
||||||
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType,
|
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType,
|
||||||
new MultiElementDependencyDescriptor(descriptor));
|
new MultiElementDescriptor(descriptor));
|
||||||
if (matchingBeans.isEmpty()) {
|
if (matchingBeans.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -1157,7 +1157,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType,
|
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType,
|
||||||
new MultiElementDependencyDescriptor(descriptor));
|
new MultiElementDescriptor(descriptor));
|
||||||
if (matchingBeans.isEmpty()) {
|
if (matchingBeans.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -1181,7 +1181,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType,
|
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType,
|
||||||
new MultiElementDependencyDescriptor(descriptor));
|
new MultiElementDescriptor(descriptor));
|
||||||
if (matchingBeans.isEmpty()) {
|
if (matchingBeans.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -1248,25 +1248,27 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (String candidateName : candidateNames) {
|
for (String candidate : candidateNames) {
|
||||||
if (!isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, descriptor)) {
|
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
|
||||||
addCandidateEntry(result, candidateName, descriptor, requiredType);
|
addCandidateEntry(result, candidate, descriptor, requiredType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (result.isEmpty() && !indicatesMultipleBeans(requiredType)) {
|
if (result.isEmpty() && !indicatesMultipleBeans(requiredType)) {
|
||||||
// Consider fallback matches if the first pass failed to find anything...
|
// Consider fallback matches if the first pass failed to find anything...
|
||||||
DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
|
DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
|
||||||
for (String candidateName : candidateNames) {
|
for (String candidate : candidateNames) {
|
||||||
if (!isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, fallbackDescriptor)) {
|
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor)) {
|
||||||
addCandidateEntry(result, candidateName, descriptor, requiredType);
|
addCandidateEntry(result, candidate, descriptor, requiredType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (result.isEmpty() && !(descriptor instanceof MultiElementDependencyDescriptor)) {
|
if (result.isEmpty()) {
|
||||||
// Consider self references as a final pass...
|
// Consider self references as a final pass...
|
||||||
// but not as collection elements, just for direct dependency declarations.
|
// but in the case of a dependency collection, not the very same bean itself.
|
||||||
for (String candidateName : candidateNames) {
|
for (String candidate : candidateNames) {
|
||||||
if (isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, fallbackDescriptor)) {
|
if (isSelfReference(beanName, candidate) &&
|
||||||
addCandidateEntry(result, candidateName, descriptor, requiredType);
|
(!(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<String, Object> candidates, String candidateName,
|
private void addCandidateEntry(Map<String, Object> candidates, String candidateName,
|
||||||
DependencyDescriptor descriptor, Class<?> requiredType) {
|
DependencyDescriptor descriptor, Class<?> requiredType) {
|
||||||
|
|
||||||
if (descriptor instanceof MultiElementDependencyDescriptor || containsSingleton(candidateName)) {
|
if (descriptor instanceof MultiElementDescriptor || containsSingleton(candidateName)) {
|
||||||
candidates.put(candidateName, descriptor.resolveCandidate(candidateName, requiredType, this));
|
candidates.put(candidateName, descriptor.resolveCandidate(candidateName, requiredType, this));
|
||||||
}
|
}
|
||||||
else {
|
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);
|
super(original);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import java.lang.annotation.ElementType;
|
|||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
|
import java.util.List;
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@@ -615,6 +616,15 @@ public class ConfigurationClassPostProcessorTests {
|
|||||||
assertSame(ctx.getBean(BarImpl.class), ctx.getBean(FooImpl.class).bar);
|
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<TestBean> testBeans;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public TestBean thing() {
|
||||||
|
return new TestBean();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user