Support FactoryBean bean definition attributes

Update `getTypeForFactoryBean` detection so that a bean definition
attribute can be used to supply the result. This commit allows projects
such as Spring Data to provide the result that would be supplied by
`getObjectType` early so that we don't need to initialize the
`FactoryBean` unnecessarily.

Closes gh-23338
This commit is contained in:
Phillip Webb
2019-07-23 08:21:42 +01:00
committed by Juergen Hoeller
parent a0e462581f
commit 71a5308c78
4 changed files with 98 additions and 5 deletions

View File

@@ -22,9 +22,13 @@ import org.junit.Test;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
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.core.type.AnnotationMetadata;
import static org.assertj.core.api.Assertions.assertThat;
@@ -66,6 +70,16 @@ public class ConfigurationWithFactoryBeanBeanEarlyDeductionTests {
assertPostFreeze(GenericClassConfiguration.class);
}
@Test
public void preFreezeAttribute() {
assertPreFreeze(AttributeClassConfiguration.class);
}
@Test
public void postFreezeAttribute() {
assertPostFreeze(AttributeClassConfiguration.class);
}
private void assertPostFreeze(Class<?> configurationClass) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
configurationClass);
@@ -138,7 +152,29 @@ public class ConfigurationWithFactoryBeanBeanEarlyDeductionTests {
}
static class MyBean {
@Configuration
@Import(AttributeClassRegistrar.class)
static class AttributeClassConfiguration {
}
static class AttributeClassRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
BeanDefinition definition = BeanDefinitionBuilder.genericBeanDefinition(
RawWithAbstractObjectTypeFactoryBean.class).getBeanDefinition();
definition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, MyBean.class);
registry.registerBeanDefinition("myBean", definition);
}
}
abstract static class AbstractMyBean {
}
static class MyBean extends AbstractMyBean {
}
static class TestFactoryBean<T> implements FactoryBean<T> {
@@ -169,4 +205,20 @@ public class ConfigurationWithFactoryBeanBeanEarlyDeductionTests {
}
static class RawWithAbstractObjectTypeFactoryBean implements FactoryBean<Object> {
private final Object object = new MyBean();
@Override
public Object getObject() throws Exception {
return object;
}
@Override
public Class<?> getObjectType() {
return MyBean.class;
}
}
}