Consistently evaluate defaultCandidate flag on constructors and methods

Closes gh-33762
This commit is contained in:
Juergen Hoeller 2024-10-21 13:53:28 +02:00
parent 6f9413ba31
commit ee1fe8a1e9
2 changed files with 74 additions and 12 deletions

View File

@ -154,26 +154,35 @@ public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwa
*/
@Override
public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) {
boolean match = super.isAutowireCandidate(bdHolder, descriptor);
if (match) {
match = checkQualifiers(bdHolder, descriptor.getAnnotations());
if (match) {
MethodParameter methodParam = descriptor.getMethodParameter();
if (methodParam != null) {
Method method = methodParam.getMethod();
if (method == null || void.class == method.getReturnType()) {
match = checkQualifiers(bdHolder, methodParam.getMethodAnnotations());
if (!super.isAutowireCandidate(bdHolder, descriptor)) {
return false;
}
Boolean checked = checkQualifiers(bdHolder, descriptor.getAnnotations());
if (checked != Boolean.FALSE) {
MethodParameter methodParam = descriptor.getMethodParameter();
if (methodParam != null) {
Method method = methodParam.getMethod();
if (method == null || void.class == method.getReturnType()) {
Boolean methodChecked = checkQualifiers(bdHolder, methodParam.getMethodAnnotations());
if (methodChecked != null && checked == null) {
checked = methodChecked;
}
}
}
}
return match;
return (checked == Boolean.TRUE ||
(checked == null && ((RootBeanDefinition) bdHolder.getBeanDefinition()).isDefaultCandidate()));
}
/**
* Match the given qualifier annotations against the candidate bean definition.
* @return {@code false} if a qualifier has been found but not matched,
* {@code true} if a qualifier has been found and matched,
* {@code null} if no qualifier has been found at all
*/
protected boolean checkQualifiers(BeanDefinitionHolder bdHolder, Annotation[] annotationsToSearch) {
@Nullable
protected Boolean checkQualifiers(BeanDefinitionHolder bdHolder, Annotation[] annotationsToSearch) {
boolean qualifierFound = false;
if (!ObjectUtils.isEmpty(annotationsToSearch)) {
SimpleTypeConverter typeConverter = new SimpleTypeConverter();
@ -217,7 +226,7 @@ public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwa
}
}
}
return (qualifierFound || ((RootBeanDefinition) bdHolder.getBeanDefinition()).isDefaultCandidate());
return (qualifierFound ? true : null);
}
/**

View File

@ -195,6 +195,28 @@ class BeanMethodQualificationTests {
ctx.close();
}
@Test
void customWithConstructor() {
AnnotationConfigApplicationContext ctx = context(CustomConfig.class, CustomPojoWithConstructor.class);
CustomPojoWithConstructor pojo = ctx.getBean(CustomPojoWithConstructor.class);
assertThat(pojo.plainBean).isNull();
assertThat(pojo.testBean.getName()).isEqualTo("interesting");
ctx.close();
}
@Test
void customWithMethod() {
AnnotationConfigApplicationContext ctx = context(CustomConfig.class, CustomPojoWithMethod.class);
CustomPojoWithMethod pojo = ctx.getBean(CustomPojoWithMethod.class);
assertThat(pojo.plainBean).isNull();
assertThat(pojo.testBean.getName()).isEqualTo("interesting");
ctx.close();
}
@Test
void beanNamesForAnnotation() {
AnnotationConfigApplicationContext ctx = context(StandardConfig.class);
@ -327,6 +349,7 @@ class BeanMethodQualificationTests {
}
}
@Configuration
static class EffectivePrimaryConfig {
@ -346,6 +369,7 @@ class BeanMethodQualificationTests {
}
}
@Component @Lazy
static class StandardPojo {
@ -418,6 +442,35 @@ class BeanMethodQualificationTests {
}
@InterestingPojo
static class CustomPojoWithConstructor {
TestBean plainBean;
TestBean testBean;
public CustomPojoWithConstructor(Optional<TestBean> plainBean, @InterestingNeed TestBean testBean) {
this.plainBean = plainBean.orElse(null);
this.testBean = testBean;
}
}
@InterestingPojo
static class CustomPojoWithMethod {
TestBean plainBean;
TestBean testBean;
@Autowired
public void applyDependencies(Optional<TestBean> plainBean, @InterestingNeed TestBean testBean) {
this.plainBean = plainBean.orElse(null);
this.testBean = testBean;
}
}
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@interface Boring {