Skip to content

Commit 5c85732

Browse files
committed
ConfigurationClassParser uses unified ImportStack with chained import analysis
Issue: SPR-14517 (cherry picked from commit d96a66a) (cherry picked from commit ff878ea)
1 parent 4e94e84 commit 5c85732

File tree

2 files changed

+24
-19
lines changed

2 files changed

+24
-19
lines changed

spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClass.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -103,7 +103,7 @@ public ConfigurationClass(MetadataReader metadataReader, ConfigurationClass impo
103103
public ConfigurationClass(Class<?> clazz, String beanName) {
104104
Assert.hasText(beanName, "Bean name must not be null");
105105
this.metadata = new StandardAnnotationMetadata(clazz, true);
106-
this.resource = new DescriptiveResource(clazz.toString());
106+
this.resource = new DescriptiveResource(clazz.getName());
107107
this.beanName = beanName;
108108
}
109109

@@ -117,7 +117,7 @@ public ConfigurationClass(Class<?> clazz, String beanName) {
117117
*/
118118
public ConfigurationClass(Class<?> clazz, ConfigurationClass importedBy) {
119119
this.metadata = new StandardAnnotationMetadata(clazz, true);
120-
this.resource = new DescriptiveResource(clazz.toString());
120+
this.resource = new DescriptiveResource(clazz.getName());
121121
this.importedBy.add(importedBy);
122122
}
123123

@@ -233,7 +233,7 @@ public int hashCode() {
233233

234234
@Override
235235
public String toString() {
236-
return "ConfigurationClass:beanName=" + this.beanName + ",resource=" + this.resource;
236+
return "ConfigurationClass: beanName '" + this.beanName + "', " + this.resource;
237237
}
238238

239239

spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ public int compare(DeferredImportSelectorHolder o1, DeferredImportSelectorHolder
134134

135135
private final List<String> propertySourceNames = new ArrayList<String>();
136136

137-
private ImportStack importStack = new ImportStack();
137+
private final ImportStack importStack = new ImportStack();
138138

139139
private List<DeferredImportSelectorHolder> deferredImportSelectors;
140140

@@ -177,7 +177,7 @@ else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).h
177177
catch (BeanDefinitionStoreException ex) {
178178
throw ex;
179179
}
180-
catch (Exception ex) {
180+
catch (Throwable ex) {
181181
throw new BeanDefinitionStoreException(
182182
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
183183
}
@@ -269,16 +269,7 @@ protected final SourceClass doProcessConfigurationClass(ConfigurationClass confi
269269
// Check the set of scanned definitions for any further config classes and parse recursively if necessary
270270
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
271271
if (ConfigurationClassUtils.checkConfigurationClassCandidate(holder.getBeanDefinition(), this.metadataReaderFactory)) {
272-
// Provide isolated circular import detection for scanned classes,
273-
// since the initial registration did not come explicitly.
274-
ImportStack previousStack = this.importStack;
275-
this.importStack = new ImportStack();
276-
try {
277-
parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());
278-
}
279-
finally {
280-
this.importStack = previousStack;
281-
}
272+
parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());
282273
}
283274
}
284275
}
@@ -472,7 +463,7 @@ private void processDeferredImportSelectors() {
472463
catch (BeanDefinitionStoreException ex) {
473464
throw ex;
474465
}
475-
catch (Exception ex) {
466+
catch (Throwable ex) {
476467
throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" +
477468
configClass.getMetadata().getClassName() + "]", ex);
478469
}
@@ -486,7 +477,7 @@ private void processImports(ConfigurationClass configClass, SourceClass currentS
486477
return;
487478
}
488479

489-
if (checkForCircularImports && this.importStack.contains(configClass)) {
480+
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
490481
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
491482
}
492483
else {
@@ -529,7 +520,7 @@ else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
529520
catch (BeanDefinitionStoreException ex) {
530521
throw ex;
531522
}
532-
catch (Exception ex) {
523+
catch (Throwable ex) {
533524
throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" +
534525
configClass.getMetadata().getClassName() + "]", ex);
535526
}
@@ -539,6 +530,20 @@ else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
539530
}
540531
}
541532

533+
private boolean isChainedImportOnStack(ConfigurationClass configClass) {
534+
if (this.importStack.contains(configClass)) {
535+
String configClassName = configClass.getMetadata().getClassName();
536+
AnnotationMetadata importingClass = this.importStack.getImportingClassFor(configClassName);
537+
while (importingClass != null) {
538+
if (configClassName.equals(importingClass.getClassName())) {
539+
return true;
540+
}
541+
importingClass = this.importStack.getImportingClassFor(importingClass.getClassName());
542+
}
543+
}
544+
return false;
545+
}
546+
542547
/**
543548
* Invoke {@link ResourceLoaderAware}, {@link BeanClassLoaderAware} and
544549
* {@link BeanFactoryAware} contracts if implemented by the given {@code bean}.

0 commit comments

Comments
 (0)