Support String values for factoryBeanObjectType attribute on bean def

To allow us to determine the type that Spring Integration’s
GatewayProxyFactoryBean will create, the bean definition created by
MessagingGatewayRegistrar needs to set the factoryBeanObjectType
attribute. The current implementation of BeanTypeRegistry requires the
attribute’s value to be a Class, however this would require Spring
Integration’s namespace handler to load the class and class loading
should be avoided in namespace handlers.

This commit updates BeanTypeRegistry so that it supports both Class and
String values for the factoryBeanObjectType. If the value is a String
it will interpret it as a class name and attempt to load it.

See gh-2811
This commit is contained in:
Andy Wilkinson 2015-04-16 09:42:50 +01:00
parent ebb8d0c55f
commit 337673b31d
2 changed files with 59 additions and 12 deletions

View File

@ -54,6 +54,7 @@ import org.springframework.util.StringUtils;
* </ul>
*
* @author Phillip Webb
* @author Andy Wilkinson
* @since 1.2.0
*/
abstract class BeanTypeRegistry {
@ -115,13 +116,26 @@ abstract class BeanTypeRegistry {
definition.getFactoryMethodName());
Class<?> generic = ResolvableType.forMethodReturnType(method)
.as(FactoryBean.class).resolveGeneric();
if ((generic == null || generic.equals(Object.class))
&& definition.hasAttribute(FACTORY_BEAN_OBJECT_TYPE)) {
generic = (Class<?>) definition.getAttribute(FACTORY_BEAN_OBJECT_TYPE);
if (generic == null || generic.equals(Object.class)) {
generic = determineTypeFromDefinitionAttribute(factoryDefinition);
}
return generic;
}
private Class<?> determineTypeFromDefinitionAttribute(BeanDefinition definition)
throws ClassNotFoundException, LinkageError {
if (definition.hasAttribute(FACTORY_BEAN_OBJECT_TYPE)) {
Object attributeObject = definition.getAttribute(FACTORY_BEAN_OBJECT_TYPE);
if (attributeObject instanceof Class<?>) {
return (Class<?>) attributeObject;
}
else if (attributeObject instanceof String) {
return ClassUtils.forName((String) attributeObject, null);
}
}
return Object.class;
}
private Class<?> getDirectFactoryBeanGeneric(
ConfigurableListableBeanFactory beanFactory, BeanDefinition definition,
String name) throws ClassNotFoundException, LinkageError {
@ -129,9 +143,8 @@ abstract class BeanTypeRegistry {
beanFactory.getBeanClassLoader());
Class<?> generic = ResolvableType.forClass(factoryBeanClass)
.as(FactoryBean.class).resolveGeneric();
if ((generic == null || generic.equals(Object.class))
&& definition.hasAttribute(FACTORY_BEAN_OBJECT_TYPE)) {
generic = (Class<?>) definition.getAttribute(FACTORY_BEAN_OBJECT_TYPE);
if (generic == null || generic.equals(Object.class)) {
generic = determineTypeFromDefinitionAttribute(definition);
}
return generic;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2013 the original author or authors.
* Copyright 2012-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -43,6 +43,7 @@ import static org.junit.Assert.assertTrue;
* @author Dave Syer
* @author Phillip Webb
* @author Jakub Kubrynski
* @author Andy Wilkinson
*/
@SuppressWarnings("resource")
public class ConditionalOnMissingBeanTests {
@ -157,8 +158,18 @@ public class ConditionalOnMissingBeanTests {
}
@Test
public void testOnMissingBeanConditionWithNonspecificFactoryBean() {
this.context.register(NonspecificFactoryBeanConfiguration.class,
public void testOnMissingBeanConditionWithNonspecificFactoryBeanWithClassAttribute() {
this.context.register(NonspecificFactoryBeanClassAttributeConfiguration.class,
ConditionalOnFactoryBean.class,
PropertyPlaceholderAutoConfiguration.class);
this.context.refresh();
assertThat(this.context.getBean(ExampleBean.class).toString(),
equalTo("fromFactory"));
}
@Test
public void testOnMissingBeanConditionWithNonspecificFactoryBeanWithStringAttribute() {
this.context.register(NonspecificFactoryBeanStringAttributeConfiguration.class,
ConditionalOnFactoryBean.class,
PropertyPlaceholderAutoConfiguration.class);
this.context.refresh();
@ -211,11 +222,11 @@ public class ConditionalOnMissingBeanTests {
}
@Configuration
@Import(NonspecificFactoryBeanRegistrar.class)
protected static class NonspecificFactoryBeanConfiguration {
@Import(NonspecificFactoryBeanClassAttributeRegistrar.class)
protected static class NonspecificFactoryBeanClassAttributeConfiguration {
}
protected static class NonspecificFactoryBeanRegistrar implements
protected static class NonspecificFactoryBeanClassAttributeRegistrar implements
ImportBeanDefinitionRegistrar {
@Override
@ -232,6 +243,29 @@ public class ConditionalOnMissingBeanTests {
}
@Configuration
@Import(NonspecificFactoryBeanClassAttributeRegistrar.class)
protected static class NonspecificFactoryBeanStringAttributeConfiguration {
}
protected static class NonspecificFactoryBeanStringAttributeRegistrar implements
ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata meta,
BeanDefinitionRegistry registry) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(NonspecificFactoryBean.class);
builder.addConstructorArgValue("foo");
builder.getBeanDefinition()
.setAttribute(OnBeanCondition.FACTORY_BEAN_OBJECT_TYPE,
ExampleBean.class.getName());
registry.registerBeanDefinition("exampleBeanFactoryBean",
builder.getBeanDefinition());
}
}
@Configuration
@Import(FactoryBeanRegistrar.class)
protected static class RegisteredFactoryBeanConfiguration {