diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClass.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClass.java index 1da728c9f2..994a7d2822 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClass.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClass.java @@ -61,8 +61,9 @@ final class ConfigurationClass { private final Map> importedResources = new LinkedHashMap>(); - private final Set importBeanDefinitionRegistrars = - new LinkedHashSet(); + private final Map importBeanDefinitionRegistrars = + new LinkedHashMap(); + /** * Create a new {@link ConfigurationClass} with the given name. @@ -175,12 +176,12 @@ final class ConfigurationClass { this.importedResources.put(importedResource, readerClass); } - public void addImportBeanDefinitionRegistrar(ImportBeanDefinitionRegistrar registrar) { - this.importBeanDefinitionRegistrars.add(registrar); + public void addImportBeanDefinitionRegistrar(ImportBeanDefinitionRegistrar registrar, AnnotationMetadata importingClassMetadata) { + this.importBeanDefinitionRegistrars.put(registrar, importingClassMetadata); } - public Set getImportBeanDefinitionRegistrars() { - return Collections.unmodifiableSet(this.importBeanDefinitionRegistrars); + public Map getImportBeanDefinitionRegistrars() { + return this.importBeanDefinitionRegistrars; } public Map> getImportedResources() { diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java index 9dd371278e..3a9d7408d9 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java @@ -136,7 +136,7 @@ class ConfigurationClassBeanDefinitionReader { loadBeanDefinitionsForBeanMethod(beanMethod); } loadBeanDefinitionsFromImportedResources(configClass.getImportedResources()); - loadBeanDefinitionsFromRegistrars(configClass.getMetadata(), configClass.getImportBeanDefinitionRegistrars()); + loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars()); } private void removeBeanDefinition(ConfigurationClass configClass) { @@ -314,11 +314,9 @@ class ConfigurationClassBeanDefinitionReader { } } - private void loadBeanDefinitionsFromRegistrars(AnnotationMetadata importingClassMetadata, - Set importBeanDefinitionRegistrars) { - - for (ImportBeanDefinitionRegistrar registrar : importBeanDefinitionRegistrars) { - registrar.registerBeanDefinitions(importingClassMetadata, this.registry); + private void loadBeanDefinitionsFromRegistrars(Map registrars) { + for (Map.Entry entry : registrars.entrySet()) { + entry.getKey().registerBeanDefinitions(entry.getValue(), this.registry); } } 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 ff3d66991b..04b0717c43 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 @@ -223,8 +223,7 @@ class ConfigurationClassParser { // process any @PropertySource annotations for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable( - sourceClass.getMetadata(), PropertySources.class, - org.springframework.context.annotation.PropertySource.class)) { + sourceClass.getMetadata(), PropertySources.class, org.springframework.context.annotation.PropertySource.class)) { processPropertySource(propertySource); } @@ -246,7 +245,7 @@ class ConfigurationClassParser { } // process any @Import annotations - processImports(configClass, getImports(sourceClass), true); + processImports(configClass, sourceClass, getImports(sourceClass), true); // process any @ImportResource annotations if (sourceClass.getMetadata().isAnnotated(ImportResource.class.getName())) { @@ -378,7 +377,7 @@ class ConfigurationClassParser { try { ConfigurationClass configClass = deferredImport.getConfigurationClass(); String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata()); - processImports(configClass, asSourceClasses(imports), false); + processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false); } catch (Exception ex) { throw new BeanDefinitionStoreException("Failed to load bean class: ", ex); @@ -387,10 +386,10 @@ class ConfigurationClassParser { this.deferredImportSelectors.clear(); } - private void processImports(ConfigurationClass configClass, Collection sourceClasses, boolean checkForCircularImports) - throws IOException { + private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass, + Collection importCandidates, boolean checkForCircularImports) throws IOException { - if (sourceClasses.isEmpty()) { + if (importCandidates.isEmpty()) { return; } if (checkForCircularImports && this.importStack.contains(configClass)) { @@ -398,9 +397,8 @@ class ConfigurationClassParser { } else { this.importStack.push(configClass); - AnnotationMetadata importingClassMetadata = configClass.getMetadata(); try { - for (SourceClass candidate : sourceClasses) { + for (SourceClass candidate : importCandidates) { if (candidate.isAssignable(ImportSelector.class)) { // the candidate class is an ImportSelector -> delegate to it to determine imports Class candidateClass = candidate.loadClass(); @@ -410,9 +408,9 @@ class ConfigurationClassParser { this.deferredImportSelectors.add(new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector)); } else { - String[] importClassNames = selector.selectImports(importingClassMetadata); + String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); Collection importSourceClasses = asSourceClasses(importClassNames); - processImports(configClass, importSourceClasses, false); + processImports(configClass, currentSourceClass, importSourceClasses, false); } } else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) { @@ -420,11 +418,11 @@ class ConfigurationClassParser { Class candidateClass = candidate.loadClass(); ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class); invokeAwareMethods(registrar); - configClass.addImportBeanDefinitionRegistrar(registrar); + configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata()); } else { // candidate class not an ImportSelector or ImportBeanDefinitionRegistrar -> process it as a @Configuration class - this.importStack.registerImport(importingClassMetadata, candidate.getMetadata().getClassName()); + this.importStack.registerImport(currentSourceClass.getMetadata(), candidate.getMetadata().getClassName()); processConfigurationClass(candidate.asConfigClass(configClass)); } } @@ -485,8 +483,7 @@ class ConfigurationClassParser { return propertySources; } - private PropertySource collatePropertySources(String name, - List> propertySources) { + private PropertySource collatePropertySources(String name, List> propertySources) { if (propertySources.size() == 1) { return propertySources.get(0); } @@ -558,7 +555,6 @@ class ConfigurationClassParser { interface ImportRegistry { AnnotationMetadata getImportingClassFor(String importedClass); - } 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 896170e048..8a35bb7d55 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 {