Deferred import processing reliably detects late registration attempts

Issue: SPR-12838
This commit is contained in:
Juergen Hoeller 2015-03-23 19:58:02 +01:00
parent 7f845f7b5e
commit 1a8c6fa5ee
1 changed files with 14 additions and 9 deletions

View File

@ -133,7 +133,7 @@ class ConfigurationClassParser {
private final ImportStack importStack = new ImportStack(); private final ImportStack importStack = new ImportStack();
private final List<DeferredImportSelectorHolder> deferredImportSelectors = new LinkedList<DeferredImportSelectorHolder>(); private List<DeferredImportSelectorHolder> deferredImportSelectors;
/** /**
@ -156,6 +156,8 @@ class ConfigurationClassParser {
public void parse(Set<BeanDefinitionHolder> configCandidates) { public void parse(Set<BeanDefinitionHolder> configCandidates) {
this.deferredImportSelectors = new LinkedList<DeferredImportSelectorHolder>();
for (BeanDefinitionHolder holder : configCandidates) { for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition(); BeanDefinition bd = holder.getBeanDefinition();
try { try {
@ -177,6 +179,7 @@ class ConfigurationClassParser {
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex); "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
} }
} }
processDeferredImportSelectors(); processDeferredImportSelectors();
} }
@ -269,7 +272,7 @@ class ConfigurationClassParser {
} }
// Process any @Import annotations // Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), true, false); processImports(configClass, sourceClass, getImports(sourceClass), true);
// Process any @ImportResource annotations // Process any @ImportResource annotations
if (sourceClass.getMetadata().isAnnotated(ImportResource.class.getName())) { if (sourceClass.getMetadata().isAnnotated(ImportResource.class.getName())) {
@ -427,12 +430,15 @@ class ConfigurationClassParser {
} }
private void processDeferredImportSelectors() { private void processDeferredImportSelectors() {
Collections.sort(this.deferredImportSelectors, DEFERRED_IMPORT_COMPARATOR); List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
for (DeferredImportSelectorHolder deferredImport : this.deferredImportSelectors) { this.deferredImportSelectors = null;
Collections.sort(deferredImports, DEFERRED_IMPORT_COMPARATOR);
for (DeferredImportSelectorHolder deferredImport : deferredImports) {
ConfigurationClass configClass = deferredImport.getConfigurationClass(); ConfigurationClass configClass = deferredImport.getConfigurationClass();
try { try {
String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata()); String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata());
processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false, true); processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false);
} }
catch (BeanDefinitionStoreException ex) { catch (BeanDefinitionStoreException ex) {
throw ex; throw ex;
@ -442,11 +448,10 @@ class ConfigurationClassParser {
configClass.getMetadata().getClassName() + "]", ex); configClass.getMetadata().getClassName() + "]", ex);
} }
} }
this.deferredImportSelectors.clear();
} }
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass, private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, boolean checkForCircularImports, boolean deferred) throws IOException { Collection<SourceClass> importCandidates, boolean checkForCircularImports) throws IOException {
if (importCandidates.isEmpty()) { if (importCandidates.isEmpty()) {
return; return;
@ -464,14 +469,14 @@ class ConfigurationClassParser {
Class<?> candidateClass = candidate.loadClass(); Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class); ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
invokeAwareMethods(selector); invokeAwareMethods(selector);
if (!deferred && selector instanceof DeferredImportSelector) { if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {
this.deferredImportSelectors.add( this.deferredImportSelectors.add(
new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector)); new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
} }
else { else {
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames); Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
processImports(configClass, currentSourceClass, importSourceClasses, false, false); processImports(configClass, currentSourceClass, importSourceClasses, false);
} }
} }
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) { else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {