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 @Override
public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) { public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) {
boolean match = super.isAutowireCandidate(bdHolder, descriptor); if (!super.isAutowireCandidate(bdHolder, descriptor)) {
if (match) { return false;
match = checkQualifiers(bdHolder, descriptor.getAnnotations()); }
if (match) { Boolean checked = checkQualifiers(bdHolder, descriptor.getAnnotations());
MethodParameter methodParam = descriptor.getMethodParameter(); if (checked != Boolean.FALSE) {
if (methodParam != null) { MethodParameter methodParam = descriptor.getMethodParameter();
Method method = methodParam.getMethod(); if (methodParam != null) {
if (method == null || void.class == method.getReturnType()) { Method method = methodParam.getMethod();
match = checkQualifiers(bdHolder, methodParam.getMethodAnnotations()); 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. * 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; boolean qualifierFound = false;
if (!ObjectUtils.isEmpty(annotationsToSearch)) { if (!ObjectUtils.isEmpty(annotationsToSearch)) {
SimpleTypeConverter typeConverter = new SimpleTypeConverter(); 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(); 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 @Test
void beanNamesForAnnotation() { void beanNamesForAnnotation() {
AnnotationConfigApplicationContext ctx = context(StandardConfig.class); AnnotationConfigApplicationContext ctx = context(StandardConfig.class);
@ -327,6 +349,7 @@ class BeanMethodQualificationTests {
} }
} }
@Configuration @Configuration
static class EffectivePrimaryConfig { static class EffectivePrimaryConfig {
@ -346,6 +369,7 @@ class BeanMethodQualificationTests {
} }
} }
@Component @Lazy @Component @Lazy
static class StandardPojo { 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 @Qualifier
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@interface Boring { @interface Boring {