diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java index 06e2f9bf93..b54b562692 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java @@ -26,9 +26,11 @@ import org.springframework.beans.BeansException; 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.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.core.Ordered; +import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.ClassMetadata; import org.springframework.core.type.classreading.MetadataReader; @@ -122,7 +124,7 @@ public class ConfigurationClassPostProcessor extends AbstractConfigurationClassP if (beanDef.isAbstract() && !includeAbstractBeanDefs) continue; - if (isConfigurationClassBeanDefinition(beanDef)) + if (isConfigurationClassBeanDefinition(beanDef, beanFactory.getBeanClassLoader())) configBeanDefs.registerBeanDefinition(beanName, beanDef); } @@ -181,14 +183,20 @@ public class ConfigurationClassPostProcessor extends AbstractConfigurationClassP * @return whether the BeanDefinition's beanClass (or its ancestry) is * {@link Configuration}-annotated, false if no beanClass is specified. */ - private static boolean isConfigurationClassBeanDefinition(BeanDefinition beanDef) { + private static boolean isConfigurationClassBeanDefinition(BeanDefinition beanDef, ClassLoader classLoader) { + + // accommodating SPR-5655 + Assert.isInstanceOf(AbstractBeanDefinition.class, beanDef); + if(((AbstractBeanDefinition) beanDef).hasBeanClass()) + return AnnotationUtils.findAnnotation( + ((AbstractBeanDefinition)beanDef).getBeanClass(), Configuration.class) != null; String className = beanDef.getBeanClassName(); while (className != null && !(className.equals(Object.class.getName()))) { try { MetadataReader metadataReader = - new SimpleMetadataReaderFactory().getMetadataReader(className); + new SimpleMetadataReaderFactory(classLoader).getMetadataReader(className); AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata(); ClassMetadata classMetadata = metadataReader.getClassMetadata(); diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/ConfigurationPostProcessorTests.java b/org.springframework.context/src/test/java/org/springframework/context/annotation/ConfigurationPostProcessorTests.java index 99d6086cca..35239cfb68 100644 --- a/org.springframework.context/src/test/java/org/springframework/context/annotation/ConfigurationPostProcessorTests.java +++ b/org.springframework.context/src/test/java/org/springframework/context/annotation/ConfigurationPostProcessorTests.java @@ -143,5 +143,34 @@ public class ConfigurationPostProcessorTests { final Foo foo; public Bar(Foo foo) { this.foo = foo; } } - + + /** + * Tests the fix for SPR-5655, a special workaround that prefers reflection + * over ASM if a bean class is already loaded. + */ + @Test + public void testAlreadyLoadedConfigurationClasses() { + DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); + beanFactory.registerBeanDefinition("unloadedConfig", + rootBeanDefinition(UnloadedConfig.class.getName()).getBeanDefinition()); + beanFactory.registerBeanDefinition("loadedConfig", + rootBeanDefinition(LoadedConfig.class).getBeanDefinition()); + new ConfigurationClassPostProcessor() .postProcessBeanFactory(beanFactory); + beanFactory.getBean("foo"); + beanFactory.getBean("bar"); + } + + @Configuration + static class UnloadedConfig { + public @Bean Foo foo() { + return new Foo(); + } + } + + @Configuration + static class LoadedConfig { + public @Bean Bar bar() { + return new Bar(new Foo()); + } + } }