Resolve factoryBeanClass if necessary
Update `AbstractAutowireCapableBeanFactory.getTypeForFactoryBean` to use fallback to `determineTargetType` if the factory bean definition does not have a resolved class. This is required for the case where a `@Configuration` class is picked up via component scanning and has a bean type that has not yet been resolved. Closes gh-23338
This commit is contained in:
parent
6eca9e7cc9
commit
89d150d398
|
@ -858,9 +858,16 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
|||
// Try to obtain the FactoryBean's object type from its factory method
|
||||
// declaration without instantiating the containing bean at all.
|
||||
BeanDefinition factoryBeanDefinition = getBeanDefinition(factoryBeanName);
|
||||
if (factoryBeanDefinition instanceof AbstractBeanDefinition &&
|
||||
((AbstractBeanDefinition) factoryBeanDefinition).hasBeanClass()) {
|
||||
Class<?> factoryBeanClass = ((AbstractBeanDefinition) factoryBeanDefinition).getBeanClass();
|
||||
Class<?> factoryBeanClass = null;
|
||||
if (factoryBeanDefinition instanceof AbstractBeanDefinition
|
||||
&& ((AbstractBeanDefinition) factoryBeanDefinition).hasBeanClass()) {
|
||||
factoryBeanClass = ((AbstractBeanDefinition) factoryBeanDefinition).getBeanClass();
|
||||
}
|
||||
else {
|
||||
RootBeanDefinition fbmbd = getMergedBeanDefinition(factoryBeanName, factoryBeanDefinition);
|
||||
factoryBeanClass = determineTargetType(factoryBeanName, fbmbd, new Class<?>[] { Object.class });
|
||||
}
|
||||
if (factoryBeanClass != null) {
|
||||
result = getTypeForFactoryBeanFromMethod(factoryBeanClass, factoryMethodName);
|
||||
if (result.resolve() != null) {
|
||||
return result;
|
||||
|
|
|
@ -28,6 +28,8 @@ import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
|||
import org.springframework.beans.factory.support.AbstractBeanFactory;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.GenericBeanDefinition;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
@ -80,6 +82,32 @@ public class ConfigurationWithFactoryBeanBeanEarlyDeductionTests {
|
|||
assertPostFreeze(AttributeClassConfiguration.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preFreezeUnresolvedGenericFactoryBean() {
|
||||
// Covers the case where a @Configuration is picked up via component scanning
|
||||
// and its bean definition only has a String bean class. In such cases
|
||||
// beanDefinition.hasBeanClass() returns false so we need to actually
|
||||
// call determineTargetType ourselves
|
||||
GenericBeanDefinition factoryBeanDefinition = new GenericBeanDefinition();
|
||||
factoryBeanDefinition.setBeanClassName(GenericClassConfiguration.class.getName());
|
||||
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
|
||||
beanDefinition.setBeanClass(FactoryBean.class);
|
||||
beanDefinition.setFactoryBeanName("factoryBean");
|
||||
beanDefinition.setFactoryMethodName("myBean");
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
try {
|
||||
context.registerBeanDefinition("factoryBean", factoryBeanDefinition);
|
||||
context.registerBeanDefinition("myBean", beanDefinition);
|
||||
NameCollectingBeanFactoryPostProcessor postProcessor = new NameCollectingBeanFactoryPostProcessor();
|
||||
context.addBeanFactoryPostProcessor(postProcessor);
|
||||
context.refresh();
|
||||
assertContainsMyBeanName(postProcessor.getNames());
|
||||
}
|
||||
finally {
|
||||
context.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void assertPostFreeze(Class<?> configurationClass) {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
|
||||
configurationClass);
|
||||
|
@ -90,11 +118,16 @@ public class ConfigurationWithFactoryBeanBeanEarlyDeductionTests {
|
|||
BeanFactoryPostProcessor... postProcessors) {
|
||||
NameCollectingBeanFactoryPostProcessor postProcessor = new NameCollectingBeanFactoryPostProcessor();
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
Arrays.stream(postProcessors).forEach(context::addBeanFactoryPostProcessor);
|
||||
context.addBeanFactoryPostProcessor(postProcessor);
|
||||
context.register(configurationClass);
|
||||
context.refresh();
|
||||
assertContainsMyBeanName(postProcessor.getNames());
|
||||
try {
|
||||
Arrays.stream(postProcessors).forEach(context::addBeanFactoryPostProcessor);
|
||||
context.addBeanFactoryPostProcessor(postProcessor);
|
||||
context.register(configurationClass);
|
||||
context.refresh();
|
||||
assertContainsMyBeanName(postProcessor.getNames());
|
||||
}
|
||||
finally {
|
||||
context.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void assertContainsMyBeanName(AnnotationConfigApplicationContext context) {
|
||||
|
|
Loading…
Reference in New Issue