diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java index 9e879a96a5..355e73d5ab 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java @@ -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); diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/support/QualifierAnnotationAutowireBeanFactoryTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/support/QualifierAnnotationAutowireBeanFactoryTests.java index f9ecb7e6c7..12d0fbdbf7 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/support/QualifierAnnotationAutowireBeanFactoryTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/support/QualifierAnnotationAutowireBeanFactoryTests.java @@ -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; + }