Skip to content

Commit ff878ea

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

File tree

2 files changed

+22
-17
lines changed

2 files changed

+22
-17
lines changed

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

Lines changed: 2 additions & 2 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.
@@ -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
@@ -139,7 +139,7 @@ public int compare(DeferredImportSelectorHolder o1, DeferredImportSelectorHolder
139139

140140
private final List<String> propertySourceNames = new ArrayList<String>();
141141

142-
private ImportStack importStack = new ImportStack();
142+
private final ImportStack importStack = new ImportStack();
143143

144144
private List<DeferredImportSelectorHolder> deferredImportSelectors;
145145

@@ -182,7 +182,7 @@ else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).h
182182
catch (BeanDefinitionStoreException ex) {
183183
throw ex;
184184
}
185-
catch (Exception ex) {
185+
catch (Throwable ex) {
186186
throw new BeanDefinitionStoreException(
187187
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
188188
}
@@ -276,16 +276,7 @@ protected final SourceClass doProcessConfigurationClass(ConfigurationClass confi
276276
// Check the set of scanned definitions for any further config classes and parse recursively if necessary
277277
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
278278
if (ConfigurationClassUtils.checkConfigurationClassCandidate(holder.getBeanDefinition(), this.metadataReaderFactory)) {
279-
// Provide isolated circular import detection for scanned classes,
280-
// since the initial registration did not come explicitly.
281-
ImportStack previousStack = this.importStack;
282-
this.importStack = new ImportStack();
283-
try {
284-
parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());
285-
}
286-
finally {
287-
this.importStack = previousStack;
288-
}
279+
parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());
289280
}
290281
}
291282
}
@@ -493,7 +484,7 @@ private void processDeferredImportSelectors() {
493484
catch (BeanDefinitionStoreException ex) {
494485
throw ex;
495486
}
496-
catch (Exception ex) {
487+
catch (Throwable ex) {
497488
throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" +
498489
configClass.getMetadata().getClassName() + "]", ex);
499490
}
@@ -507,7 +498,7 @@ private void processImports(ConfigurationClass configClass, SourceClass currentS
507498
return;
508499
}
509500

510-
if (checkForCircularImports && this.importStack.contains(configClass)) {
501+
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
511502
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
512503
}
513504
else {
@@ -550,7 +541,7 @@ else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
550541
catch (BeanDefinitionStoreException ex) {
551542
throw ex;
552543
}
553-
catch (Exception ex) {
544+
catch (Throwable ex) {
554545
throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" +
555546
configClass.getMetadata().getClassName() + "]", ex);
556547
}
@@ -560,6 +551,20 @@ else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
560551
}
561552
}
562553

554+
private boolean isChainedImportOnStack(ConfigurationClass configClass) {
555+
if (this.importStack.contains(configClass)) {
556+
String configClassName = configClass.getMetadata().getClassName();
557+
AnnotationMetadata importingClass = this.importStack.getImportingClassFor(configClassName);
558+
while (importingClass != null) {
559+
if (configClassName.equals(importingClass.getClassName())) {
560+
return true;
561+
}
562+
importingClass = this.importStack.getImportingClassFor(importingClass.getClassName());
563+
}
564+
}
565+
return false;
566+
}
567+
563568
/**
564569
* Invoke {@link ResourceLoaderAware}, {@link BeanClassLoaderAware} and
565570
* {@link BeanFactoryAware} contracts if implemented by the given {@code bean}.

0 commit comments

Comments
 (0)