Fix qualifier resolution for aliased name against parent factory
Backport Bot / build (push) Waiting to run Details
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:ubuntu-latest name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:ubuntu-latest name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:23], map[id:ubuntu-latest name:Linux]) (push) Waiting to run Details
Deploy Docs / Dispatch docs deployment (push) Waiting to run Details

Closes gh-34644
This commit is contained in:
Juergen Hoeller 2025-03-25 00:08:42 +01:00
parent d8f8e76791
commit 37fb79e8ff
2 changed files with 69 additions and 21 deletions

View File

@ -895,7 +895,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
String beanName, DependencyDescriptor descriptor, AutowireCandidateResolver resolver)
throws NoSuchBeanDefinitionException {
String bdName = BeanFactoryUtils.transformedBeanName(beanName);
String bdName = transformedBeanName(beanName);
if (containsBeanDefinition(bdName)) {
return isAutowireCandidate(beanName, getMergedLocalBeanDefinition(bdName), descriptor, resolver);
}
@ -929,7 +929,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
protected boolean isAutowireCandidate(String beanName, RootBeanDefinition mbd,
DependencyDescriptor descriptor, AutowireCandidateResolver resolver) {
String bdName = BeanFactoryUtils.transformedBeanName(beanName);
String bdName = transformedBeanName(beanName);
resolveBeanClass(mbd, bdName);
if (mbd.isFactoryMethodUnique && mbd.factoryMethodToIntrospect == null) {
new ConstructorResolver(this).resolveFactoryMethodIfPossible(mbd);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -21,12 +21,13 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.testfixture.beans.TestBean;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.MethodParameter;
import org.springframework.util.ClassUtils;
@ -43,14 +44,17 @@ class QualifierAnnotationAutowireBeanFactoryTests {
private static final String MARK = "mark";
private final DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
@Test
void testAutowireCandidateDefaultWithIrrelevantDescriptor() throws Exception {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
ConstructorArgumentValues cavs = new ConstructorArgumentValues();
cavs.addGenericArgumentValue(JUERGEN);
RootBeanDefinition rbd = new RootBeanDefinition(Person.class, cavs, null);
lbf.registerBeanDefinition(JUERGEN, rbd);
assertThat(lbf.isAutowireCandidate(JUERGEN, null)).isTrue();
assertThat(lbf.isAutowireCandidate(JUERGEN,
new DependencyDescriptor(Person.class.getDeclaredField("name"), false))).isTrue();
@ -60,12 +64,12 @@ class QualifierAnnotationAutowireBeanFactoryTests {
@Test
void testAutowireCandidateExplicitlyFalseWithIrrelevantDescriptor() throws Exception {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
ConstructorArgumentValues cavs = new ConstructorArgumentValues();
cavs.addGenericArgumentValue(JUERGEN);
RootBeanDefinition rbd = new RootBeanDefinition(Person.class, cavs, null);
rbd.setAutowireCandidate(false);
lbf.registerBeanDefinition(JUERGEN, rbd);
assertThat(lbf.isAutowireCandidate(JUERGEN, null)).isFalse();
assertThat(lbf.isAutowireCandidate(JUERGEN,
new DependencyDescriptor(Person.class.getDeclaredField("name"), false))).isFalse();
@ -73,44 +77,46 @@ class QualifierAnnotationAutowireBeanFactoryTests {
new DependencyDescriptor(Person.class.getDeclaredField("name"), true))).isFalse();
}
@Disabled
@Test
void testAutowireCandidateWithFieldDescriptor() throws Exception {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
lbf.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
ConstructorArgumentValues cavs1 = new ConstructorArgumentValues();
cavs1.addGenericArgumentValue(JUERGEN);
RootBeanDefinition person1 = new RootBeanDefinition(Person.class, cavs1, null);
person1.addQualifier(new AutowireCandidateQualifier(TestQualifier.class));
lbf.registerBeanDefinition(JUERGEN, person1);
ConstructorArgumentValues cavs2 = new ConstructorArgumentValues();
cavs2.addGenericArgumentValue(MARK);
RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null);
lbf.registerBeanDefinition(MARK, person2);
DependencyDescriptor qualifiedDescriptor = new DependencyDescriptor(
QualifiedTestBean.class.getDeclaredField("qualified"), false);
DependencyDescriptor nonqualifiedDescriptor = new DependencyDescriptor(
QualifiedTestBean.class.getDeclaredField("nonqualified"), false);
assertThat(lbf.isAutowireCandidate(JUERGEN, null)).isTrue();
assertThat(lbf.isAutowireCandidate(JUERGEN, nonqualifiedDescriptor)).isTrue();
assertThat(lbf.isAutowireCandidate(JUERGEN, qualifiedDescriptor)).isTrue();
assertThat(lbf.isAutowireCandidate(MARK, null)).isTrue();
assertThat(lbf.isAutowireCandidate(MARK, nonqualifiedDescriptor)).isTrue();
assertThat(lbf.isAutowireCandidate(MARK, qualifiedDescriptor)).isFalse();
}
@Test
void testAutowireCandidateExplicitlyFalseWithFieldDescriptor() throws Exception {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
ConstructorArgumentValues cavs = new ConstructorArgumentValues();
cavs.addGenericArgumentValue(JUERGEN);
RootBeanDefinition person = new RootBeanDefinition(Person.class, cavs, null);
person.setAutowireCandidate(false);
person.addQualifier(new AutowireCandidateQualifier(TestQualifier.class));
lbf.registerBeanDefinition(JUERGEN, person);
DependencyDescriptor qualifiedDescriptor = new DependencyDescriptor(
QualifiedTestBean.class.getDeclaredField("qualified"), false);
DependencyDescriptor nonqualifiedDescriptor = new DependencyDescriptor(
QualifiedTestBean.class.getDeclaredField("nonqualified"), false);
assertThat(lbf.isAutowireCandidate(JUERGEN, null)).isFalse();
assertThat(lbf.isAutowireCandidate(JUERGEN, nonqualifiedDescriptor)).isFalse();
assertThat(lbf.isAutowireCandidate(JUERGEN, qualifiedDescriptor)).isFalse();
@ -118,56 +124,61 @@ class QualifierAnnotationAutowireBeanFactoryTests {
@Test
void testAutowireCandidateWithShortClassName() throws Exception {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
ConstructorArgumentValues cavs = new ConstructorArgumentValues();
cavs.addGenericArgumentValue(JUERGEN);
RootBeanDefinition person = new RootBeanDefinition(Person.class, cavs, null);
person.addQualifier(new AutowireCandidateQualifier(ClassUtils.getShortName(TestQualifier.class)));
lbf.registerBeanDefinition(JUERGEN, person);
DependencyDescriptor qualifiedDescriptor = new DependencyDescriptor(
QualifiedTestBean.class.getDeclaredField("qualified"), false);
DependencyDescriptor nonqualifiedDescriptor = new DependencyDescriptor(
QualifiedTestBean.class.getDeclaredField("nonqualified"), false);
assertThat(lbf.isAutowireCandidate(JUERGEN, null)).isTrue();
assertThat(lbf.isAutowireCandidate(JUERGEN, nonqualifiedDescriptor)).isTrue();
assertThat(lbf.isAutowireCandidate(JUERGEN, qualifiedDescriptor)).isTrue();
}
@Disabled
@Test
void testAutowireCandidateWithConstructorDescriptor() throws Exception {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
lbf.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
ConstructorArgumentValues cavs1 = new ConstructorArgumentValues();
cavs1.addGenericArgumentValue(JUERGEN);
RootBeanDefinition person1 = new RootBeanDefinition(Person.class, cavs1, null);
person1.addQualifier(new AutowireCandidateQualifier(TestQualifier.class));
lbf.registerBeanDefinition(JUERGEN, person1);
ConstructorArgumentValues cavs2 = new ConstructorArgumentValues();
cavs2.addGenericArgumentValue(MARK);
RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null);
lbf.registerBeanDefinition(MARK, person2);
MethodParameter param = new MethodParameter(QualifiedTestBean.class.getDeclaredConstructor(Person.class), 0);
DependencyDescriptor qualifiedDescriptor = new DependencyDescriptor(param, false);
param.initParameterNameDiscovery(new DefaultParameterNameDiscoverer());
assertThat(param.getParameterName()).isEqualTo("tpb");
assertThat(lbf.isAutowireCandidate(JUERGEN, null)).isTrue();
assertThat(lbf.isAutowireCandidate(JUERGEN, qualifiedDescriptor)).isTrue();
assertThat(lbf.isAutowireCandidate(MARK, qualifiedDescriptor)).isFalse();
}
@Disabled
@Test
void testAutowireCandidateWithMethodDescriptor() throws Exception {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
lbf.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
ConstructorArgumentValues cavs1 = new ConstructorArgumentValues();
cavs1.addGenericArgumentValue(JUERGEN);
RootBeanDefinition person1 = new RootBeanDefinition(Person.class, cavs1, null);
person1.addQualifier(new AutowireCandidateQualifier(TestQualifier.class));
lbf.registerBeanDefinition(JUERGEN, person1);
ConstructorArgumentValues cavs2 = new ConstructorArgumentValues();
cavs2.addGenericArgumentValue(MARK);
RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null);
lbf.registerBeanDefinition(MARK, person2);
MethodParameter qualifiedParam =
new MethodParameter(QualifiedTestBean.class.getDeclaredMethod("autowireQualified", Person.class), 0);
MethodParameter nonqualifiedParam =
@ -175,37 +186,70 @@ class QualifierAnnotationAutowireBeanFactoryTests {
DependencyDescriptor qualifiedDescriptor = new DependencyDescriptor(qualifiedParam, false);
DependencyDescriptor nonqualifiedDescriptor = new DependencyDescriptor(nonqualifiedParam, false);
qualifiedParam.initParameterNameDiscovery(new DefaultParameterNameDiscoverer());
assertThat(qualifiedParam.getParameterName()).isEqualTo("tpb");
nonqualifiedParam.initParameterNameDiscovery(new DefaultParameterNameDiscoverer());
assertThat(qualifiedParam.getParameterName()).isEqualTo("tpb");
assertThat(nonqualifiedParam.getParameterName()).isEqualTo("tpb");
assertThat(lbf.isAutowireCandidate(JUERGEN, null)).isTrue();
assertThat(lbf.isAutowireCandidate(JUERGEN, nonqualifiedDescriptor)).isTrue();
assertThat(lbf.isAutowireCandidate(JUERGEN, qualifiedDescriptor)).isTrue();
assertThat(lbf.isAutowireCandidate(MARK, null)).isTrue();
assertThat(lbf.isAutowireCandidate(MARK, nonqualifiedDescriptor)).isTrue();
assertThat(lbf.isAutowireCandidate(MARK, qualifiedDescriptor)).isFalse();
}
@Test
void testAutowireCandidateWithMultipleCandidatesDescriptor() throws Exception {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
ConstructorArgumentValues cavs1 = new ConstructorArgumentValues();
cavs1.addGenericArgumentValue(JUERGEN);
RootBeanDefinition person1 = new RootBeanDefinition(Person.class, cavs1, null);
person1.addQualifier(new AutowireCandidateQualifier(TestQualifier.class));
lbf.registerBeanDefinition(JUERGEN, person1);
ConstructorArgumentValues cavs2 = new ConstructorArgumentValues();
cavs2.addGenericArgumentValue(MARK);
RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null);
person2.addQualifier(new AutowireCandidateQualifier(TestQualifier.class));
lbf.registerBeanDefinition(MARK, person2);
DependencyDescriptor qualifiedDescriptor = new DependencyDescriptor(
new MethodParameter(QualifiedTestBean.class.getDeclaredConstructor(Person.class), 0),
false);
assertThat(lbf.isAutowireCandidate(JUERGEN, qualifiedDescriptor)).isTrue();
assertThat(lbf.isAutowireCandidate(MARK, qualifiedDescriptor)).isTrue();
}
@Test
void autowireBeanByTypeWithQualifierPrecedence() throws Exception {
lbf.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class);
RootBeanDefinition bd2 = new RootBeanDefinition(TestBean.class);
lbf.registerBeanDefinition("testBean", bd);
lbf.registerBeanDefinition("spouse", bd2);
lbf.registerAlias("test", "testBean");
assertThat(lbf.resolveDependency(new DependencyDescriptor(getClass().getDeclaredField("testBean"), true), null))
.isSameAs(lbf.getBean("spouse"));
}
@Test
void autowireBeanByTypeWithQualifierPrecedenceInAncestor() throws Exception {
DefaultListableBeanFactory parent = new DefaultListableBeanFactory();
parent.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class);
RootBeanDefinition bd2 = new RootBeanDefinition(TestBean.class);
parent.registerBeanDefinition("test", bd);
parent.registerBeanDefinition("spouse", bd2);
parent.registerAlias("test", "testBean");
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(parent);
lbf.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
assertThat(lbf.resolveDependency(new DependencyDescriptor(getClass().getDeclaredField("testBean"), true), null))
.isSameAs(lbf.getBean("spouse"));
}
@SuppressWarnings("unused")
private static class QualifiedTestBean {
@ -247,4 +291,8 @@ class QualifierAnnotationAutowireBeanFactoryTests {
private @interface TestQualifier {
}
@Qualifier("spouse")
private TestBean testBean;
}