From 337673b31d827cb59bcb5c6e7d24fc8c31769ffa Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 16 Apr 2015 09:42:50 +0100 Subject: [PATCH] Support String values for factoryBeanObjectType attribute on bean def MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- .../condition/BeanTypeRegistry.java | 25 +++++++--- .../ConditionalOnMissingBeanTests.java | 46 ++++++++++++++++--- 2 files changed, 59 insertions(+), 12 deletions(-) diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/BeanTypeRegistry.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/BeanTypeRegistry.java index 39b7348eca4..013991b20f0 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/BeanTypeRegistry.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/BeanTypeRegistry.java @@ -54,6 +54,7 @@ import org.springframework.util.StringUtils; * * * @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; } diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnMissingBeanTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnMissingBeanTests.java index 80ef06f9a71..507c2549aa5 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnMissingBeanTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnMissingBeanTests.java @@ -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 {