Skip to content

Commit 4a0fa69

Browse files
committed
Injection support for Collection/Map beans and self references
Issue: SPR-13585 Issue: SPR-12180 Issue: SPR-7915 Issue: SPR-8450
1 parent 64e77de commit 4a0fa69

File tree

3 files changed

+217
-62
lines changed

3 files changed

+217
-62
lines changed

spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java

+62-48
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -45,7 +45,6 @@
4545
import javax.inject.Provider;
4646

4747
import org.springframework.beans.BeansException;
48-
import org.springframework.beans.FatalBeanException;
4948
import org.springframework.beans.TypeConverter;
5049
import org.springframework.beans.factory.BeanCreationException;
5150
import org.springframework.beans.factory.BeanCurrentlyInCreationException;
@@ -113,6 +112,9 @@
113112
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
114113
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
115114

115+
private static final Object NOT_MULTIPLE_BEANS = new Object();
116+
117+
116118
private static Class<?> javaUtilOptionalClass = null;
117119

118120
private static Class<?> javaxInjectProviderClass = null;
@@ -615,10 +617,12 @@ public <A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> a
615617

616618
@Override
617619
public void registerResolvableDependency(Class<?> dependencyType, Object autowiredValue) {
618-
Assert.notNull(dependencyType, "Type must not be null");
620+
Assert.notNull(dependencyType, "Dependency type must not be null");
619621
if (autowiredValue != null) {
620-
Assert.isTrue((autowiredValue instanceof ObjectFactory || dependencyType.isInstance(autowiredValue)),
621-
"Value [" + autowiredValue + "] does not implement specified type [" + dependencyType.getName() + "]");
622+
if (!(autowiredValue instanceof ObjectFactory || dependencyType.isInstance(autowiredValue))) {
623+
throw new IllegalArgumentException("Value [" + autowiredValue +
624+
"] does not implement specified dependency type [" + dependencyType.getName() + "]");
625+
}
622626
this.resolvableDependencies.put(dependencyType, autowiredValue);
623627
}
624628
}
@@ -1034,15 +1038,54 @@ public Object doResolveDependency(DependencyDescriptor descriptor, String beanNa
10341038
converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
10351039
}
10361040

1041+
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
1042+
if (multipleBeans != null && multipleBeans != NOT_MULTIPLE_BEANS) {
1043+
return multipleBeans;
1044+
}
1045+
1046+
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
1047+
if (matchingBeans.isEmpty()) {
1048+
if (descriptor.isRequired()) {
1049+
raiseNoSuchBeanDefinitionException(type, descriptor.getResolvableType().toString(), descriptor);
1050+
}
1051+
return null;
1052+
}
1053+
if (matchingBeans.size() > 1) {
1054+
String primaryBeanName = determineAutowireCandidate(matchingBeans, descriptor);
1055+
if (primaryBeanName == null) {
1056+
if (multipleBeans == NOT_MULTIPLE_BEANS || descriptor.isRequired()) {
1057+
throw new NoUniqueBeanDefinitionException(type, matchingBeans.keySet());
1058+
}
1059+
else {
1060+
// In case of an optional Collection/Map, silently ignore a non-unique case:
1061+
// possibly it was meant to be an empty collection of multiple regular beans
1062+
// (before 4.3 in particular when we didn't even look for collection beans).
1063+
return null;
1064+
}
1065+
}
1066+
if (autowiredBeanNames != null) {
1067+
autowiredBeanNames.add(primaryBeanName);
1068+
}
1069+
return matchingBeans.get(primaryBeanName);
1070+
}
1071+
// We have exactly one match.
1072+
Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
1073+
if (autowiredBeanNames != null) {
1074+
autowiredBeanNames.add(entry.getKey());
1075+
}
1076+
return entry.getValue();
1077+
}
1078+
1079+
private Object resolveMultipleBeans(DependencyDescriptor descriptor, String beanName,
1080+
Set<String> autowiredBeanNames, TypeConverter typeConverter) {
1081+
1082+
Class<?> type = descriptor.getDependencyType();
10371083
if (type.isArray()) {
10381084
Class<?> componentType = type.getComponentType();
10391085
DependencyDescriptor targetDesc = new DependencyDescriptor(descriptor);
10401086
targetDesc.increaseNestingLevel();
10411087
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType, targetDesc);
10421088
if (matchingBeans.isEmpty()) {
1043-
if (descriptor.isRequired()) {
1044-
raiseNoSuchBeanDefinitionException(componentType, "array of " + componentType.getName(), descriptor);
1045-
}
10461089
return null;
10471090
}
10481091
if (autowiredBeanNames != null) {
@@ -1058,18 +1101,12 @@ public Object doResolveDependency(DependencyDescriptor descriptor, String beanNa
10581101
else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
10591102
Class<?> elementType = descriptor.getCollectionType();
10601103
if (elementType == null) {
1061-
if (descriptor.isRequired()) {
1062-
throw new FatalBeanException("No element type declared for collection [" + type.getName() + "]");
1063-
}
10641104
return null;
10651105
}
10661106
DependencyDescriptor targetDesc = new DependencyDescriptor(descriptor);
10671107
targetDesc.increaseNestingLevel();
10681108
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType, targetDesc);
10691109
if (matchingBeans.isEmpty()) {
1070-
if (descriptor.isRequired()) {
1071-
raiseNoSuchBeanDefinitionException(elementType, "collection of " + elementType.getName(), descriptor);
1072-
}
10731110
return null;
10741111
}
10751112
if (autowiredBeanNames != null) {
@@ -1085,26 +1122,16 @@ else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
10851122
else if (Map.class.isAssignableFrom(type) && type.isInterface()) {
10861123
Class<?> keyType = descriptor.getMapKeyType();
10871124
if (String.class != keyType) {
1088-
if (descriptor.isRequired()) {
1089-
throw new FatalBeanException("Key type [" + keyType + "] of map [" + type.getName() +
1090-
"] must be [java.lang.String]");
1091-
}
10921125
return null;
10931126
}
10941127
Class<?> valueType = descriptor.getMapValueType();
10951128
if (valueType == null) {
1096-
if (descriptor.isRequired()) {
1097-
throw new FatalBeanException("No value type declared for map [" + type.getName() + "]");
1098-
}
10991129
return null;
11001130
}
11011131
DependencyDescriptor targetDesc = new DependencyDescriptor(descriptor);
11021132
targetDesc.increaseNestingLevel();
11031133
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType, targetDesc);
11041134
if (matchingBeans.isEmpty()) {
1105-
if (descriptor.isRequired()) {
1106-
raiseNoSuchBeanDefinitionException(valueType, "map with value type " + valueType.getName(), descriptor);
1107-
}
11081135
return null;
11091136
}
11101137
if (autowiredBeanNames != null) {
@@ -1113,29 +1140,7 @@ else if (Map.class.isAssignableFrom(type) && type.isInterface()) {
11131140
return matchingBeans;
11141141
}
11151142
else {
1116-
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
1117-
if (matchingBeans.isEmpty()) {
1118-
if (descriptor.isRequired()) {
1119-
raiseNoSuchBeanDefinitionException(type, "", descriptor);
1120-
}
1121-
return null;
1122-
}
1123-
if (matchingBeans.size() > 1) {
1124-
String primaryBeanName = determineAutowireCandidate(matchingBeans, descriptor);
1125-
if (primaryBeanName == null) {
1126-
throw new NoUniqueBeanDefinitionException(type, matchingBeans.keySet());
1127-
}
1128-
if (autowiredBeanNames != null) {
1129-
autowiredBeanNames.add(primaryBeanName);
1130-
}
1131-
return matchingBeans.get(primaryBeanName);
1132-
}
1133-
// We have exactly one match.
1134-
Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
1135-
if (autowiredBeanNames != null) {
1136-
autowiredBeanNames.add(entry.getKey());
1137-
}
1138-
return entry.getValue();
1143+
return NOT_MULTIPLE_BEANS;
11391144
}
11401145
}
11411146

@@ -1193,12 +1198,21 @@ protected Map<String, Object> findAutowireCandidates(
11931198
}
11941199
}
11951200
if (result.isEmpty()) {
1201+
// Consider fallback matches if the first pass failed to find anything...
11961202
DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
11971203
for (String candidateName : candidateNames) {
1198-
if (!candidateName.equals(beanName) && isAutowireCandidate(candidateName, fallbackDescriptor)) {
1204+
if (!isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, fallbackDescriptor)) {
11991205
result.put(candidateName, getBean(candidateName));
12001206
}
12011207
}
1208+
if (result.isEmpty()) {
1209+
// Consider self references before as a final pass
1210+
for (String candidateName : candidateNames) {
1211+
if (isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, fallbackDescriptor)) {
1212+
result.put(candidateName, getBean(candidateName));
1213+
}
1214+
}
1215+
}
12021216
}
12031217
return result;
12041218
}

0 commit comments

Comments
 (0)