Skip to content

Commit 49237fc

Browse files
committed
Merge branch '6.2.x'
# Conflicts: # spring-beans/src/main/java/org/springframework/beans/factory/annotation/QualifierAnnotationAutowireCandidateResolver.java # spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java
2 parents 783299d + bce1445 commit 49237fc

File tree

3 files changed

+182
-89
lines changed

3 files changed

+182
-89
lines changed

spring-beans/src/main/java/org/springframework/beans/factory/annotation/QualifierAnnotationAutowireCandidateResolver.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,6 @@ public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDesc
172172
* {@code true} if a qualifier has been found and matched,
173173
* {@code null} if no qualifier has been found at all
174174
*/
175-
176175
protected @Nullable Boolean checkQualifiers(BeanDefinitionHolder bdHolder, Annotation[] annotationsToSearch) {
177176
boolean qualifierFound = false;
178177
if (!ObjectUtils.isEmpty(annotationsToSearch)) {
@@ -364,6 +363,14 @@ public boolean hasQualifier(DependencyDescriptor descriptor) {
364363
return true;
365364
}
366365
}
366+
MethodParameter methodParam = descriptor.getMethodParameter();
367+
if (methodParam != null) {
368+
for (Annotation annotation : methodParam.getMethodAnnotations()) {
369+
if (isQualifier(annotation.annotationType())) {
370+
return true;
371+
}
372+
}
373+
}
367374
return false;
368375
}
369376

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

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1651,7 +1651,7 @@ else if (descriptor.supportsLazyResolution()) {
16511651
return doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
16521652
}
16531653

1654-
@SuppressWarnings("NullAway") // Dataflow analysis limitation
1654+
@SuppressWarnings("NullAway") // Dataflow analysis limitation
16551655
public @Nullable Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
16561656
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
16571657

@@ -1977,7 +1977,8 @@ protected Map<String, Object> findAutowireCandidates(
19771977
DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
19781978
for (String candidate : candidateNames) {
19791979
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor) &&
1980-
(!multiple || getAutowireCandidateResolver().hasQualifier(descriptor))) {
1980+
(!multiple || matchesBeanName(candidate, descriptor.getDependencyName()) ||
1981+
getAutowireCandidateResolver().hasQualifier(descriptor))) {
19811982
addCandidateEntry(result, candidate, descriptor, requiredType);
19821983
}
19831984
}
@@ -2244,12 +2245,12 @@ private String determineDefaultCandidate(Map<String, Object> candidates) {
22442245
}
22452246

22462247
/**
2247-
* Determine whether the given candidate name matches the bean name or the aliases
2248+
* Determine whether the given dependency name matches the bean name or the aliases
22482249
* stored in this bean definition.
22492250
*/
2250-
protected boolean matchesBeanName(String beanName, @Nullable String candidateName) {
2251-
return (candidateName != null &&
2252-
(candidateName.equals(beanName) || ObjectUtils.containsElement(getAliases(beanName), candidateName)));
2251+
protected boolean matchesBeanName(String beanName, @Nullable String dependencyName) {
2252+
return (dependencyName != null &&
2253+
(dependencyName.equals(beanName) || ObjectUtils.containsElement(getAliases(beanName), dependencyName)));
22532254
}
22542255

22552256
/**

spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java

Lines changed: 167 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1279,88 +1279,6 @@ void constructorInjectionWithMap() {
12791279
assertThat(bean.getTestBean().get("testBean2")).isNull();
12801280
}
12811281

1282-
@Test
1283-
void fieldInjectionWithMap() {
1284-
RootBeanDefinition bd = new RootBeanDefinition(MapFieldInjectionBean.class);
1285-
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
1286-
bf.registerBeanDefinition("annotatedBean", bd);
1287-
TestBean tb1 = new TestBean("tb1");
1288-
TestBean tb2 = new TestBean("tb2");
1289-
bf.registerSingleton("testBean1", tb1);
1290-
bf.registerSingleton("testBean2", tb2);
1291-
bf.registerAlias("testBean1", "testBean");
1292-
1293-
MapFieldInjectionBean bean = bf.getBean("annotatedBean", MapFieldInjectionBean.class);
1294-
assertThat(bean.getTestBeanMap()).hasSize(2);
1295-
assertThat(bean.getTestBeanMap()).containsKey("testBean1");
1296-
assertThat(bean.getTestBeanMap()).containsKey("testBean2");
1297-
assertThat(bean.getTestBeanMap()).containsValue(tb1);
1298-
assertThat(bean.getTestBeanMap()).containsValue(tb2);
1299-
1300-
bean = bf.getBean("annotatedBean", MapFieldInjectionBean.class);
1301-
assertThat(bean.getTestBeanMap()).hasSize(2);
1302-
assertThat(bean.getTestBeanMap()).containsKey("testBean1");
1303-
assertThat(bean.getTestBeanMap()).containsKey("testBean2");
1304-
assertThat(bean.getTestBeanMap()).containsValue(tb1);
1305-
assertThat(bean.getTestBeanMap()).containsValue(tb2);
1306-
}
1307-
1308-
@Test
1309-
void methodInjectionWithMap() {
1310-
RootBeanDefinition bd = new RootBeanDefinition(MapMethodInjectionBean.class);
1311-
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
1312-
bf.registerBeanDefinition("annotatedBean", bd);
1313-
TestBean tb = new TestBean();
1314-
bf.registerSingleton("testBean", tb);
1315-
1316-
MapMethodInjectionBean bean = bf.getBean("annotatedBean", MapMethodInjectionBean.class);
1317-
assertThat(bean.getTestBeanMap()).hasSize(1);
1318-
assertThat(bean.getTestBeanMap()).containsKey("testBean");
1319-
assertThat(bean.getTestBeanMap()).containsValue(tb);
1320-
assertThat(bean.getTestBean()).isSameAs(tb);
1321-
1322-
bean = bf.getBean("annotatedBean", MapMethodInjectionBean.class);
1323-
assertThat(bean.getTestBeanMap()).hasSize(1);
1324-
assertThat(bean.getTestBeanMap()).containsKey("testBean");
1325-
assertThat(bean.getTestBeanMap()).containsValue(tb);
1326-
assertThat(bean.getTestBean()).isSameAs(tb);
1327-
}
1328-
1329-
@Test
1330-
void methodInjectionWithMapAndMultipleMatches() {
1331-
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(MapMethodInjectionBean.class));
1332-
bf.registerBeanDefinition("testBean1", new RootBeanDefinition(TestBean.class));
1333-
bf.registerBeanDefinition("testBean2", new RootBeanDefinition(TestBean.class));
1334-
assertThatExceptionOfType(UnsatisfiedDependencyException.class).as("should have failed, more than one bean of type")
1335-
.isThrownBy(() -> bf.getBean("annotatedBean"))
1336-
.satisfies(methodParameterDeclaredOn(MapMethodInjectionBean.class));
1337-
}
1338-
1339-
@Test
1340-
void methodInjectionWithMapAndMultipleMatchesButOnlyOneAutowireCandidate() {
1341-
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(MapMethodInjectionBean.class));
1342-
bf.registerBeanDefinition("testBean1", new RootBeanDefinition(TestBean.class));
1343-
RootBeanDefinition rbd2 = new RootBeanDefinition(TestBean.class);
1344-
rbd2.setAutowireCandidate(false);
1345-
bf.registerBeanDefinition("testBean2", rbd2);
1346-
1347-
MapMethodInjectionBean bean = bf.getBean("annotatedBean", MapMethodInjectionBean.class);
1348-
TestBean tb = bf.getBean("testBean1", TestBean.class);
1349-
assertThat(bean.getTestBeanMap()).hasSize(1);
1350-
assertThat(bean.getTestBeanMap()).containsKey("testBean1");
1351-
assertThat(bean.getTestBeanMap()).containsValue(tb);
1352-
assertThat(bean.getTestBean()).isSameAs(tb);
1353-
}
1354-
1355-
@Test
1356-
void methodInjectionWithMapAndNoMatches() {
1357-
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(MapMethodInjectionBean.class));
1358-
1359-
MapMethodInjectionBean bean = bf.getBean("annotatedBean", MapMethodInjectionBean.class);
1360-
assertThat(bean.getTestBeanMap()).isNull();
1361-
assertThat(bean.getTestBean()).isNull();
1362-
}
1363-
13641282
@Test
13651283
void constructorInjectionWithTypedMapAsBean() {
13661284
RootBeanDefinition bd = new RootBeanDefinition(MapConstructorInjectionBean.class);
@@ -1413,6 +1331,19 @@ void constructorInjectionWithCustomMapAsBean() {
14131331

14141332
@Test
14151333
void constructorInjectionWithPlainHashMapAsBean() {
1334+
RootBeanDefinition bd = new RootBeanDefinition(NamedMapConstructorInjectionBean.class);
1335+
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
1336+
bf.registerBeanDefinition("annotatedBean", bd);
1337+
bf.registerBeanDefinition("testBeanMap", new RootBeanDefinition(HashMap.class));
1338+
1339+
NamedMapConstructorInjectionBean bean = bf.getBean("annotatedBean", NamedMapConstructorInjectionBean.class);
1340+
assertThat(bean.getTestBeanMap()).isSameAs(bf.getBean("testBeanMap"));
1341+
bean = bf.getBean("annotatedBean", NamedMapConstructorInjectionBean.class);
1342+
assertThat(bean.getTestBeanMap()).isSameAs(bf.getBean("testBeanMap"));
1343+
}
1344+
1345+
@Test
1346+
void constructorInjectionWithQualifiedPlainHashMapAsBean() {
14161347
RootBeanDefinition bd = new RootBeanDefinition(QualifiedMapConstructorInjectionBean.class);
14171348
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
14181349
bf.registerBeanDefinition("annotatedBean", bd);
@@ -1501,6 +1432,114 @@ void constructorInjectionWithSortedSetFallback() {
15011432
assertThat(bean.getTestBeanSet()).contains(tb1, tb2);
15021433
}
15031434

1435+
@Test
1436+
void fieldInjectionWithMap() {
1437+
RootBeanDefinition bd = new RootBeanDefinition(MapFieldInjectionBean.class);
1438+
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
1439+
bf.registerBeanDefinition("annotatedBean", bd);
1440+
TestBean tb1 = new TestBean("tb1");
1441+
TestBean tb2 = new TestBean("tb2");
1442+
bf.registerSingleton("testBean1", tb1);
1443+
bf.registerSingleton("testBean2", tb2);
1444+
bf.registerAlias("testBean1", "testBean");
1445+
1446+
MapFieldInjectionBean bean = bf.getBean("annotatedBean", MapFieldInjectionBean.class);
1447+
assertThat(bean.getTestBeanMap()).hasSize(2);
1448+
assertThat(bean.getTestBeanMap()).containsKey("testBean1");
1449+
assertThat(bean.getTestBeanMap()).containsKey("testBean2");
1450+
assertThat(bean.getTestBeanMap()).containsValue(tb1);
1451+
assertThat(bean.getTestBeanMap()).containsValue(tb2);
1452+
1453+
bean = bf.getBean("annotatedBean", MapFieldInjectionBean.class);
1454+
assertThat(bean.getTestBeanMap()).hasSize(2);
1455+
assertThat(bean.getTestBeanMap()).containsKey("testBean1");
1456+
assertThat(bean.getTestBeanMap()).containsKey("testBean2");
1457+
assertThat(bean.getTestBeanMap()).containsValue(tb1);
1458+
assertThat(bean.getTestBeanMap()).containsValue(tb2);
1459+
}
1460+
1461+
@Test
1462+
void methodInjectionWithMap() {
1463+
RootBeanDefinition bd = new RootBeanDefinition(MapMethodInjectionBean.class);
1464+
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
1465+
bf.registerBeanDefinition("annotatedBean", bd);
1466+
TestBean tb = new TestBean();
1467+
bf.registerSingleton("testBean", tb);
1468+
1469+
MapMethodInjectionBean bean = bf.getBean("annotatedBean", MapMethodInjectionBean.class);
1470+
assertThat(bean.getTestBeanMap()).hasSize(1);
1471+
assertThat(bean.getTestBeanMap()).containsKey("testBean");
1472+
assertThat(bean.getTestBeanMap()).containsValue(tb);
1473+
assertThat(bean.getTestBean()).isSameAs(tb);
1474+
1475+
bean = bf.getBean("annotatedBean", MapMethodInjectionBean.class);
1476+
assertThat(bean.getTestBeanMap()).hasSize(1);
1477+
assertThat(bean.getTestBeanMap()).containsKey("testBean");
1478+
assertThat(bean.getTestBeanMap()).containsValue(tb);
1479+
assertThat(bean.getTestBean()).isSameAs(tb);
1480+
}
1481+
1482+
@Test
1483+
void methodInjectionWithMapAndMultipleMatches() {
1484+
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(MapMethodInjectionBean.class));
1485+
bf.registerBeanDefinition("testBean1", new RootBeanDefinition(TestBean.class));
1486+
bf.registerBeanDefinition("testBean2", new RootBeanDefinition(TestBean.class));
1487+
assertThatExceptionOfType(UnsatisfiedDependencyException.class).as("should have failed, more than one bean of type")
1488+
.isThrownBy(() -> bf.getBean("annotatedBean"))
1489+
.satisfies(methodParameterDeclaredOn(MapMethodInjectionBean.class));
1490+
}
1491+
1492+
@Test
1493+
void methodInjectionWithMapAndMultipleMatchesButOnlyOneAutowireCandidate() {
1494+
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(MapMethodInjectionBean.class));
1495+
bf.registerBeanDefinition("testBean1", new RootBeanDefinition(TestBean.class));
1496+
RootBeanDefinition rbd2 = new RootBeanDefinition(TestBean.class);
1497+
rbd2.setAutowireCandidate(false);
1498+
bf.registerBeanDefinition("testBean2", rbd2);
1499+
1500+
MapMethodInjectionBean bean = bf.getBean("annotatedBean", MapMethodInjectionBean.class);
1501+
TestBean tb = bf.getBean("testBean1", TestBean.class);
1502+
assertThat(bean.getTestBeanMap()).hasSize(1);
1503+
assertThat(bean.getTestBeanMap()).containsKey("testBean1");
1504+
assertThat(bean.getTestBeanMap()).containsValue(tb);
1505+
assertThat(bean.getTestBean()).isSameAs(tb);
1506+
}
1507+
1508+
@Test
1509+
void methodInjectionWithMapAndNoMatches() {
1510+
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(MapMethodInjectionBean.class));
1511+
1512+
MapMethodInjectionBean bean = bf.getBean("annotatedBean", MapMethodInjectionBean.class);
1513+
assertThat(bean.getTestBeanMap()).isNull();
1514+
assertThat(bean.getTestBean()).isNull();
1515+
}
1516+
1517+
@Test
1518+
void methodInjectionWithPlainHashMapAsBean() {
1519+
RootBeanDefinition bd = new RootBeanDefinition(NamedMapMethodInjectionBean.class);
1520+
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
1521+
bf.registerBeanDefinition("annotatedBean", bd);
1522+
bf.registerBeanDefinition("testBeanMap", new RootBeanDefinition(HashMap.class));
1523+
1524+
NamedMapMethodInjectionBean bean = bf.getBean("annotatedBean", NamedMapMethodInjectionBean.class);
1525+
assertThat(bean.getTestBeanMap()).isSameAs(bf.getBean("testBeanMap"));
1526+
bean = bf.getBean("annotatedBean", NamedMapMethodInjectionBean.class);
1527+
assertThat(bean.getTestBeanMap()).isSameAs(bf.getBean("testBeanMap"));
1528+
}
1529+
1530+
@Test
1531+
void methodInjectionWithQualifiedPlainHashMapAsBean() {
1532+
RootBeanDefinition bd = new RootBeanDefinition(QualifiedMapMethodInjectionBean.class);
1533+
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
1534+
bf.registerBeanDefinition("annotatedBean", bd);
1535+
bf.registerBeanDefinition("myTestBeanMap", new RootBeanDefinition(HashMap.class));
1536+
1537+
QualifiedMapMethodInjectionBean bean = bf.getBean("annotatedBean", QualifiedMapMethodInjectionBean.class);
1538+
assertThat(bean.getTestBeanMap()).isSameAs(bf.getBean("myTestBeanMap"));
1539+
bean = bf.getBean("annotatedBean", QualifiedMapMethodInjectionBean.class);
1540+
assertThat(bean.getTestBeanMap()).isSameAs(bf.getBean("myTestBeanMap"));
1541+
}
1542+
15041543
@Test
15051544
void selfReference() {
15061545
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SelfInjectionBean.class));
@@ -3262,6 +3301,21 @@ public SortedMap<String, TestBean> getTestBeanMap() {
32623301
}
32633302

32643303

3304+
public static class NamedMapConstructorInjectionBean {
3305+
3306+
private Map<String, TestBean> testBeanMap;
3307+
3308+
@Autowired
3309+
public NamedMapConstructorInjectionBean(Map<String, TestBean> testBeanMap) {
3310+
this.testBeanMap = testBeanMap;
3311+
}
3312+
3313+
public Map<String, TestBean> getTestBeanMap() {
3314+
return this.testBeanMap;
3315+
}
3316+
}
3317+
3318+
32653319
public static class QualifiedMapConstructorInjectionBean {
32663320

32673321
private Map<String, TestBean> testBeanMap;
@@ -3361,6 +3415,37 @@ public Map<String, TestBean> getTestBeanMap() {
33613415
}
33623416

33633417

3418+
public static class NamedMapMethodInjectionBean {
3419+
3420+
private Map<String, TestBean> testBeanMap;
3421+
3422+
@Autowired
3423+
public void setTestBeanMap(Map<String, TestBean> testBeanMap) {
3424+
this.testBeanMap = testBeanMap;
3425+
}
3426+
3427+
public Map<String, TestBean> getTestBeanMap() {
3428+
return this.testBeanMap;
3429+
}
3430+
}
3431+
3432+
3433+
public static class QualifiedMapMethodInjectionBean {
3434+
3435+
private Map<String, TestBean> testBeanMap;
3436+
3437+
@Autowired
3438+
@Qualifier("myTestBeanMap")
3439+
public void setTestBeanMap(Map<String, TestBean> testBeanMap) {
3440+
this.testBeanMap = testBeanMap;
3441+
}
3442+
3443+
public Map<String, TestBean> getTestBeanMap() {
3444+
return this.testBeanMap;
3445+
}
3446+
}
3447+
3448+
33643449
@SuppressWarnings("serial")
33653450
public static class ObjectFactoryFieldInjectionBean implements Serializable {
33663451

0 commit comments

Comments
 (0)