diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java index fdc1dfc74de..42bc493c1f1 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java @@ -59,8 +59,6 @@ import org.springframework.core.type.filter.AssignableTypeFilter; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; -import static org.springframework.context.annotation.MetadataUtils.*; - /** * Parses a {@link Configuration} class definition, populating a collection of * {@link ConfigurationClass} objects (parsing a single Configuration class may result in @@ -172,20 +170,19 @@ class ConfigurationClassParser { /** * @return annotation metadata of superclass, {@code null} if none found or previously processed */ - protected AnnotationMetadata doProcessConfigurationClass( - ConfigurationClass configClass, AnnotationMetadata metadata) throws IOException { - + protected AnnotationMetadata doProcessConfigurationClass(ConfigurationClass configClass, AnnotationMetadata metadata) throws IOException { // recursively process any member (nested) classes first processMemberClasses(metadata); // process any @PropertySource annotations - AnnotationAttributes propertySource = attributesFor(metadata, org.springframework.context.annotation.PropertySource.class); + AnnotationAttributes propertySource = MetadataUtils.attributesFor(metadata, + org.springframework.context.annotation.PropertySource.class); if (propertySource != null) { processPropertySource(propertySource); } // process any @ComponentScan annotations - AnnotationAttributes componentScan = attributesFor(metadata, ComponentScan.class); + AnnotationAttributes componentScan = MetadataUtils.attributesFor(metadata, ComponentScan.class); if (componentScan != null) { // the config class is annotated with @ComponentScan -> perform the scan immediately Set scannedBeanDefinitions = @@ -204,12 +201,12 @@ class ConfigurationClassParser { Set visited = new LinkedHashSet(); collectImports(metadata, imports, visited); if (!imports.isEmpty()) { - processImport(configClass, imports, true); + processImport(configClass, metadata, imports, true); } // process any @ImportResource annotations if (metadata.isAnnotated(ImportResource.class.getName())) { - AnnotationAttributes importResource = attributesFor(metadata, ImportResource.class); + AnnotationAttributes importResource = MetadataUtils.attributesFor(metadata, ImportResource.class); String[] resources = importResource.getStringArray("value"); Class readerClass = importResource.getClass("reader"); for (String resource : resources) { @@ -369,13 +366,14 @@ class ConfigurationClassParser { } } - private void processImport(ConfigurationClass configClass, Collection classesToImport, boolean checkForCircularImports) throws IOException { + private void processImport(ConfigurationClass configClass, AnnotationMetadata metadata, + Collection classesToImport, boolean checkForCircularImports) throws IOException { + if (checkForCircularImports && this.importStack.contains(configClass)) { this.problemReporter.error(new CircularImportProblem(configClass, this.importStack, configClass.getMetadata())); } else { this.importStack.push(configClass); - AnnotationMetadata importingClassMetadata = configClass.getMetadata(); try { for (Object candidate : classesToImport) { Object candidateToCheck = (candidate instanceof Class ? (Class) candidate : @@ -385,7 +383,7 @@ class ConfigurationClassParser { Class candidateClass = (candidate instanceof Class ? (Class) candidate : this.resourceLoader.getClassLoader().loadClass((String) candidate)); ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class); - processImport(configClass, Arrays.asList(selector.selectImports(importingClassMetadata)), false); + processImport(configClass, metadata, Arrays.asList(selector.selectImports(metadata)), false); } else if (checkAssignability(ImportBeanDefinitionRegistrar.class, candidateToCheck)) { // the candidate class is an ImportBeanDefinitionRegistrar -> delegate to it to register additional bean definitions @@ -393,11 +391,11 @@ class ConfigurationClassParser { this.resourceLoader.getClassLoader().loadClass((String) candidate)); ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class); invokeAwareMethods(registrar); - registrar.registerBeanDefinitions(importingClassMetadata, this.registry); + registrar.registerBeanDefinitions(metadata, this.registry); } else { // candidate class not an ImportSelector or ImportBeanDefinitionRegistrar -> process it as a @Configuration class - this.importStack.registerImport(importingClassMetadata, + this.importStack.registerImport(metadata, (candidate instanceof Class ? ((Class) candidate).getName() : (String) candidate)); processConfigurationClass(candidateToCheck instanceof Class ? new ConfigurationClass((Class) candidateToCheck, true) : new ConfigurationClass((MetadataReader) candidateToCheck, true)); diff --git a/spring-tx/src/test/java/org/springframework/transaction/annotation/EnableTransactionManagementTests.java b/spring-tx/src/test/java/org/springframework/transaction/annotation/EnableTransactionManagementTests.java index 896170e048a..8a35bb7d55c 100644 --- a/spring-tx/src/test/java/org/springframework/transaction/annotation/EnableTransactionManagementTests.java +++ b/spring-tx/src/test/java/org/springframework/transaction/annotation/EnableTransactionManagementTests.java @@ -52,6 +52,17 @@ public class EnableTransactionManagementTests { assertThat("Stereotype annotation not visible", services.containsKey("testBean"), is(true)); } + @Test + public void transactionProxyIsCreatedWithEnableOnSuperclass() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + ctx.register(InheritedEnableTxConfig.class, TxManagerConfig.class); + ctx.refresh(); + TransactionalTestBean bean = ctx.getBean(TransactionalTestBean.class); + assertThat("testBean is not a proxy", AopUtils.isAopProxy(bean), is(true)); + Map services = ctx.getBeansWithAnnotation(Service.class); + assertThat("Stereotype annotation not visible", services.containsKey("testBean"), is(true)); + } + @Test public void txManagerIsResolvedOnInvocationOfTransactionalMethod() { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); @@ -97,6 +108,11 @@ public class EnableTransactionManagementTests { } + @Configuration + static class InheritedEnableTxConfig extends EnableTxConfig { + } + + @Configuration @EnableTransactionManagement(mode=AdviceMode.ASPECTJ) static class EnableAspectJTxConfig {