Skip to content

Commit a001319

Browse files
committed
Add additional shortcut for qualifier value matching target bean name
Closes gh-17677 See gh-28122
1 parent 874e61a commit a001319

File tree

4 files changed

+59
-11
lines changed

4 files changed

+59
-11
lines changed

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

+17-3
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ protected boolean checkQualifier(
282282
}
283283
if (actualValue == null && attributeName.equals(AutowireCandidateQualifier.VALUE_KEY) &&
284284
expectedValue instanceof String name && bdHolder.matchesName(name)) {
285-
// Fall back on bean name (or alias) match
285+
// Finally, check bean name (or alias) match
286286
continue;
287287
}
288288
if (actualValue == null && qualifier != null) {
@@ -333,14 +333,28 @@ public boolean isRequired(DependencyDescriptor descriptor) {
333333
*/
334334
@Override
335335
public boolean hasQualifier(DependencyDescriptor descriptor) {
336-
for (Annotation ann : descriptor.getAnnotations()) {
337-
if (isQualifier(ann.annotationType())) {
336+
for (Annotation annotation : descriptor.getAnnotations()) {
337+
if (isQualifier(annotation.annotationType())) {
338338
return true;
339339
}
340340
}
341341
return false;
342342
}
343343

344+
@Override
345+
@Nullable
346+
public String getSuggestedName(DependencyDescriptor descriptor) {
347+
for (Annotation annotation : descriptor.getAnnotations()) {
348+
if (isQualifier(annotation.annotationType())) {
349+
Object value = AnnotationUtils.getValue(annotation);
350+
if (value instanceof String str) {
351+
return str;
352+
}
353+
}
354+
}
355+
return null;
356+
}
357+
344358
/**
345359
* Determine whether the given dependency declares a value annotation.
346360
* @see Value

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

+13-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2024 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.
@@ -72,6 +72,18 @@ default boolean hasQualifier(DependencyDescriptor descriptor) {
7272
return false;
7373
}
7474

75+
/**
76+
* Determine whether a target bean name is suggested for the given dependency
77+
* (typically - but not necessarily - declared with a single-value qualifier).
78+
* @param descriptor the descriptor for the target method parameter or field
79+
* @return the qualifier value, if any
80+
* @since 6.2
81+
*/
82+
@Nullable
83+
default String getSuggestedName(DependencyDescriptor descriptor) {
84+
return null;
85+
}
86+
7587
/**
7688
* Determine whether a default value is suggested for the given dependency.
7789
* <p>The default implementation simply returns {@code null}.

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

+22-6
Original file line numberDiff line numberDiff line change
@@ -1400,9 +1400,13 @@ public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable Str
14001400
}
14011401
}
14021402

1403-
// Step 3: shortcut for declared dependency name matching target bean name
1403+
// Step 3: shortcut for declared dependency name or qualifier-suggested name matching target bean name
14041404
String dependencyName = descriptor.getDependencyName();
1405-
if (dependencyName != null && containsBean(dependencyName) &&
1405+
if (dependencyName == null || !containsBean(dependencyName)) {
1406+
String suggestedName = getAutowireCandidateResolver().getSuggestedName(descriptor);
1407+
dependencyName = (suggestedName != null && containsBean(suggestedName) ? suggestedName : null);
1408+
}
1409+
if (dependencyName != null &&
14061410
isTypeMatch(dependencyName, type) && isAutowireCandidate(dependencyName, descriptor) &&
14071411
!hasPrimaryConflict(dependencyName, type) && !isSelfReference(beanName, dependencyName)) {
14081412
if (autowiredBeanNames != null) {
@@ -1747,10 +1751,22 @@ protected String determineAutowireCandidate(Map<String, Object> candidates, Depe
17471751
if (primaryCandidate != null) {
17481752
return primaryCandidate;
17491753
}
1750-
// Step 2: check bean name match
1751-
for (String candidateName : candidates.keySet()) {
1752-
if (matchesBeanName(candidateName, descriptor.getDependencyName())) {
1753-
return candidateName;
1754+
// Step 2a: match bean name against declared dependency name
1755+
String dependencyName = descriptor.getDependencyName();
1756+
if (dependencyName != null) {
1757+
for (String beanName : candidates.keySet()) {
1758+
if (matchesBeanName(beanName, dependencyName)) {
1759+
return beanName;
1760+
}
1761+
}
1762+
}
1763+
// Step 2b: match bean name against qualifier-suggested name
1764+
String suggestedName = getAutowireCandidateResolver().getSuggestedName(descriptor);
1765+
if (suggestedName != null) {
1766+
for (String beanName : candidates.keySet()) {
1767+
if (matchesBeanName(beanName, suggestedName)) {
1768+
return beanName;
1769+
}
17541770
}
17551771
}
17561772
// Step 3: check highest priority candidate

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

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2024 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.
@@ -52,6 +52,12 @@ public boolean hasQualifier(DependencyDescriptor descriptor) {
5252
return false;
5353
}
5454

55+
@Override
56+
@Nullable
57+
public String getSuggestedName(DependencyDescriptor descriptor) {
58+
return null;
59+
}
60+
5561
@Override
5662
@Nullable
5763
public Object getSuggestedValue(DependencyDescriptor descriptor) {

0 commit comments

Comments
 (0)