Member classes get exposed to the import stack now

Issue: SPR-13101
This commit is contained in:
Juergen Hoeller 2015-06-11 09:56:03 +02:00
parent 9712a32c46
commit e97506be55
1 changed files with 21 additions and 9 deletions

View File

@ -73,6 +73,7 @@ import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.AssignableTypeFilter; import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap; import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
@ -326,7 +327,18 @@ class ConfigurationClassParser {
for (SourceClass memberClass : sourceClass.getMemberClasses()) { for (SourceClass memberClass : sourceClass.getMemberClasses()) {
if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) && if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&
!memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) { !memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {
processConfigurationClass(memberClass.asConfigClass(configClass)); if (this.importStack.contains(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
processConfigurationClass(memberClass.asConfigClass(configClass));
}
finally {
this.importStack.pop();
}
}
} }
} }
} }
@ -459,7 +471,7 @@ class ConfigurationClassParser {
} }
if (checkForCircularImports && this.importStack.contains(configClass)) { if (checkForCircularImports && this.importStack.contains(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack, configClass.getMetadata())); this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
} }
else { else {
this.importStack.push(configClass); this.importStack.push(configClass);
@ -632,7 +644,7 @@ class ConfigurationClassParser {
@Override @Override
public AnnotationMetadata getImportingClassFor(String importedClass) { public AnnotationMetadata getImportingClassFor(String importedClass) {
List<AnnotationMetadata> list = this.imports.get(importedClass); List<AnnotationMetadata> list = this.imports.get(importedClass);
return (list == null || list.isEmpty() ? null : list.get(list.size() - 1)); return (!CollectionUtils.isEmpty(list) ? list.get(list.size() - 1) : null);
} }
/** /**
@ -646,7 +658,7 @@ class ConfigurationClassParser {
Comparator<ConfigurationClass> comparator = new Comparator<ConfigurationClass>() { Comparator<ConfigurationClass> comparator = new Comparator<ConfigurationClass>() {
@Override @Override
public int compare(ConfigurationClass first, ConfigurationClass second) { public int compare(ConfigurationClass first, ConfigurationClass second) {
return first.getMetadata().getClassName().equals(second.getMetadata().getClassName()) ? 0 : 1; return (first.getMetadata().getClassName().equals(second.getMetadata().getClassName()) ? 0 : 1);
} }
}; };
return (Collections.binarySearch(this, configClass, comparator) != -1); return (Collections.binarySearch(this, configClass, comparator) != -1);
@ -659,11 +671,11 @@ class ConfigurationClassParser {
* <li>com.acme.Bar</li> * <li>com.acme.Bar</li>
* <li>com.acme.Baz</li> * <li>com.acme.Baz</li>
* </ul> * </ul>
* return "ImportStack: [Foo->Bar->Baz]". * return "[Foo->Bar->Baz]".
*/ */
@Override @Override
public String toString() { public String toString() {
StringBuilder builder = new StringBuilder("ImportStack: ["); StringBuilder builder = new StringBuilder("[");
Iterator<ConfigurationClass> iterator = iterator(); Iterator<ConfigurationClass> iterator = iterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
builder.append(iterator.next().getSimpleName()); builder.append(iterator.next().getSimpleName());
@ -862,12 +874,12 @@ class ConfigurationClassParser {
*/ */
private static class CircularImportProblem extends Problem { private static class CircularImportProblem extends Problem {
public CircularImportProblem(ConfigurationClass attemptedImport, Stack<ConfigurationClass> importStack, AnnotationMetadata metadata) { public CircularImportProblem(ConfigurationClass attemptedImport, Stack<ConfigurationClass> importStack) {
super(String.format("A circular @Import has been detected: " + super(String.format("A circular @Import has been detected: " +
"Illegal attempt by @Configuration class '%s' to import class '%s' as '%s' is " + "Illegal attempt by @Configuration class '%s' to import class '%s' as '%s' is " +
"already present in the current import stack [%s]", importStack.peek().getSimpleName(), "already present in the current import stack %s", importStack.peek().getSimpleName(),
attemptedImport.getSimpleName(), attemptedImport.getSimpleName(), importStack), attemptedImport.getSimpleName(), attemptedImport.getSimpleName(), importStack),
new Location(importStack.peek().getResource(), metadata)); new Location(importStack.peek().getResource(), attemptedImport.getMetadata()));
} }
} }