diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java index 27a59c67a32..0ed2174ca45 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java @@ -796,6 +796,22 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac @Override @Nullable protected Class getTypeForFactoryBean(String beanName, RootBeanDefinition mbd) { + if (mbd.getInstanceSupplier() != null) { + ResolvableType targetType = mbd.targetType; + if (targetType != null) { + Class result = targetType.as(FactoryBean.class).getGeneric().resolve(); + if (result != null) { + return result; + } + } + if (mbd.hasBeanClass()) { + Class result = GenericTypeResolver.resolveTypeArgument(mbd.getBeanClass(), FactoryBean.class); + if (result != null) { + return result; + } + } + } + String factoryBeanName = mbd.getFactoryBeanName(); String factoryMethodName = mbd.getFactoryMethodName(); diff --git a/spring-context/src/test/java/org/springframework/context/annotation/AnnotationConfigApplicationContextTests.java b/spring-context/src/test/java/org/springframework/context/annotation/AnnotationConfigApplicationContextTests.java index 7f9a1aafca7..39772366632 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/AnnotationConfigApplicationContextTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/AnnotationConfigApplicationContextTests.java @@ -25,10 +25,12 @@ import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation6.ComponentForScanning; import org.springframework.context.annotation6.ConfigForScanning; import org.springframework.context.annotation6.Jsr330NamedForScanning; +import org.springframework.core.ResolvableType; import org.springframework.util.ObjectUtils; import static java.lang.String.*; @@ -279,6 +281,30 @@ public class AnnotationConfigApplicationContextTests { assertSame(context, context.getBean("b", BeanB.class).applicationContext); } + @Test + public void individualBeanWithFactoryBeanSupplier() { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + context.registerBean("fb", TypedFactoryBean.class, TypedFactoryBean::new, bd -> bd.setLazyInit(true)); + context.refresh(); + + assertEquals(String.class, context.getType("fb")); + assertEquals(TypedFactoryBean.class, context.getType("&fb")); + } + + @Test + public void individualBeanWithFactoryBeanSupplierAndTargetType() { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + RootBeanDefinition bd = new RootBeanDefinition(); + bd.setInstanceSupplier(TypedFactoryBean::new); + bd.setTargetType(ResolvableType.forClassWithGenerics(FactoryBean.class, String.class)); + bd.setLazyInit(true); + context.registerBeanDefinition("fb", bd); + context.refresh(); + + assertEquals(String.class, context.getType("fb")); + assertEquals(FactoryBean.class, context.getType("&fb")); + } + @Test public void getBeanByTypeRaisesNoSuchBeanDefinitionException() { ApplicationContext context = new AnnotationConfigApplicationContext(Config.class); @@ -428,6 +454,28 @@ public class AnnotationConfigApplicationContextTests { static class BeanC {} + static class TypedFactoryBean implements FactoryBean { + + public TypedFactoryBean() { + throw new IllegalStateException(); + } + + @Override + public String getObject() { + return ""; + } + + @Override + public Class getObjectType() { + return String.class; + } + + @Override + public boolean isSingleton() { + return true; + } + } + static class UntypedFactoryBean implements FactoryBean { @Override