Consistent type-based bean lookup for RuntimeBeanReference

See gh-35101
This commit is contained in:
Juergen Hoeller 2025-06-26 14:47:54 +02:00
parent 06ef82e9a5
commit c5da405314
3 changed files with 61 additions and 5 deletions

View File

@ -87,6 +87,32 @@ public class RuntimeBeanReference implements BeanReference {
this.toParent = toParent;
}
/**
* Create a new RuntimeBeanReference to a bean of the given type.
* @param beanName name of the target bean
* @param beanType type of the target bean
* @since 7.0
*/
public RuntimeBeanReference(String beanName, Class<?> beanType) {
this(beanName, beanType, false);
}
/**
* Create a new RuntimeBeanReference to a bean of the given type,
* with the option to mark it as reference to a bean in the parent factory.
* @param beanName name of the target bean
* @param beanType type of the target bean
* @param toParent whether this is an explicit reference to a bean in the
* parent factory
* @since 7.0
*/
public RuntimeBeanReference(String beanName, Class<?> beanType, boolean toParent) {
Assert.notNull(beanType, "'beanType' must not be null");
this.beanName = beanName;
this.beanType = beanType;
this.toParent = toParent;
}
/**
* Return the requested bean name, or the fully-qualified type name

View File

@ -1588,7 +1588,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
private <T> @Nullable NamedBeanHolder<T> resolveNamedBean(
String beanName, ResolvableType requiredType, @Nullable Object @Nullable [] args) throws BeansException {
Object bean = getBean(beanName, null, args);
Object bean = (args != null ? getBean(beanName, args) : resolveBean(beanName, requiredType));
if (bean instanceof NullBean) {
return null;
}

View File

@ -26,6 +26,7 @@ import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.support.StaticListableBeanFactory;
@ -465,9 +466,9 @@ class BeanFactoryUtilsTests {
lbf.registerSingleton("sfb1", sfb1);
lbf.registerSingleton("sfb2", sfb2);
lbf.registerBeanDefinition("recipient",
new RootBeanDefinition(Recipient.class, RootBeanDefinition.AUTOWIRE_CONSTRUCTOR, false));
new RootBeanDefinition(ConstructorRecipient.class, RootBeanDefinition.AUTOWIRE_CONSTRUCTOR, false));
Recipient recipient = lbf.getBean("recipient", Recipient.class);
ConstructorRecipient recipient = lbf.getBean("recipient", ConstructorRecipient.class);
assertThat(recipient.sfb1).isSameAs(lbf.getBean("sfb1", TestBean.class));
assertThat(recipient.sfb2).isSameAs(lbf.getBean("sfb2", TestBean.class));
@ -553,6 +554,24 @@ class BeanFactoryUtilsTests {
assertThat(lbf.getBean("sfb2")).isInstanceOf(String.class);
}
@Test
void supportsMultipleTypesWithProperty() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
SupportsTypeSmartFactoryBean sfb = new SupportsTypeSmartFactoryBean();
lbf.registerSingleton("sfb", sfb);
RootBeanDefinition rbd1 = new RootBeanDefinition(PropertyRecipient.class);
rbd1.getPropertyValues().add("sfb", new RuntimeBeanReference(ITestBean.class));
lbf.registerBeanDefinition("recipient1", rbd1);
RootBeanDefinition rbd2 = new RootBeanDefinition(PropertyRecipient.class);
rbd2.getPropertyValues().add("sfb", new RuntimeBeanReference("sfb", ITestBean.class));
lbf.registerBeanDefinition("recipient2", rbd2);
assertThat(lbf.getBean("recipient1", PropertyRecipient.class).sfb).isSameAs(lbf.getBean("sfb", ITestBean.class));
assertThat(lbf.getBean("recipient2", PropertyRecipient.class).sfb).isSameAs(lbf.getBean("sfb", ITestBean.class));
}
@Retention(RetentionPolicy.RUNTIME)
@interface ControllerAdvice {
@ -650,9 +669,10 @@ class BeanFactoryUtilsTests {
}
static class Recipient {
static class ConstructorRecipient {
public Recipient(ITestBean sfb1, ITestBean sfb2, List<ITestBean> testBeanList, List<CharSequence> stringList,
public ConstructorRecipient(ITestBean sfb1, ITestBean sfb2,
List<ITestBean> testBeanList, List<CharSequence> stringList,
ObjectProvider<ITestBean> testBeanProvider, ObjectProvider<CharSequence> stringProvider) {
this.sfb1 = sfb1;
this.sfb2 = sfb2;
@ -675,4 +695,14 @@ class BeanFactoryUtilsTests {
ObjectProvider<CharSequence> stringProvider;
}
static class PropertyRecipient {
ITestBean sfb;
public void setSfb(ITestBean sfb) {
this.sfb = sfb;
}
}
}