diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/RuntimeBeanReference.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/RuntimeBeanReference.java index 80bdbdb4b1..d1198405a0 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/RuntimeBeanReference.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/RuntimeBeanReference.java @@ -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 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 f59766e14a..09c83104f3 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 @@ -1588,7 +1588,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto private @Nullable NamedBeanHolder 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; } diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/BeanFactoryUtilsTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/BeanFactoryUtilsTests.java index 9b7910ce7d..bf17cfe774 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/BeanFactoryUtilsTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/BeanFactoryUtilsTests.java @@ -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 testBeanList, List stringList, + public ConstructorRecipient(ITestBean sfb1, ITestBean sfb2, + List testBeanList, List stringList, ObjectProvider testBeanProvider, ObjectProvider stringProvider) { this.sfb1 = sfb1; this.sfb2 = sfb2; @@ -675,4 +695,14 @@ class BeanFactoryUtilsTests { ObjectProvider stringProvider; } + + static class PropertyRecipient { + + ITestBean sfb; + + public void setSfb(ITestBean sfb) { + this.sfb = sfb; + } + } + }