提交 8b4ad457 编写于 作者: C Chris Beams

Circular @Imports are now handled by registering a Problem...

Circular @Imports are now handled by registering a Problem (CircularImportProblem) as an error with the current ProblemReporter.  This eliminates the need for CircularImportException and is a more tooling-friendly approach.
上级 3ae3de19
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.config.java.support;
import static java.lang.String.*;
import java.util.Stack;
/**
* Thrown by {@link ConfigurationParser} upon detecting circular use of the {@link Import} annotation.
*
* @author Chris Beams
* @see Import
* @see ImportStack
* @see ImportStackHolder
*/
@SuppressWarnings("serial")
class CircularImportException extends IllegalStateException {
public CircularImportException(ConfigurationClass attemptedImport, Stack<ConfigurationClass> currentImportStack) {
super(format("A circular @Import has been detected: " +
"Illegal attempt by @Configuration class '%s' to import class '%s' as '%s' is " +
"already present in the current import stack [%s]",
currentImportStack.peek().getSimpleName(), attemptedImport.getSimpleName(),
attemptedImport.getSimpleName(), currentImportStack));
}
}
......@@ -104,7 +104,7 @@ public class ConfigurationClassPostProcessor extends AbstractConfigurationClassP
*/
@Override
protected ConfigurationParser createConfigurationParser() {
return new ConfigurationParser(beanFactory.getBeanClassLoader());
return new ConfigurationParser(this.getProblemReporter(), beanFactory.getBeanClassLoader());
}
/**
......
......@@ -15,20 +15,27 @@
*/
package org.springframework.config.java.support;
import static java.lang.String.*;
import static org.springframework.config.java.support.MutableAnnotationUtils.*;
import static org.springframework.config.java.support.Util.*;
import static org.springframework.util.ClassUtils.*;
import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.Stack;
import org.springframework.asm.AnnotationVisitor;
import org.springframework.asm.ClassAdapter;
import org.springframework.asm.ClassReader;
import org.springframework.asm.MethodVisitor;
import org.springframework.asm.Opcodes;
import org.springframework.asm.commons.EmptyVisitor;
import org.springframework.beans.factory.parsing.Location;
import org.springframework.beans.factory.parsing.Problem;
import org.springframework.beans.factory.parsing.ProblemReporter;
import org.springframework.config.java.Configuration;
import org.springframework.config.java.Import;
import org.springframework.core.io.FileSystemResource;
/**
......@@ -43,15 +50,18 @@ class ConfigurationClassVisitor extends ClassAdapter {
private final ConfigurationClass configClass;
private final ConfigurationModel model;
private final ProblemReporter problemReporter;
private final HashMap<String, ConfigurationClass> innerClasses = new HashMap<String, ConfigurationClass>();
private boolean processInnerClasses = true;
private final ClassLoader classLoader;
public ConfigurationClassVisitor(ConfigurationClass configClass, ConfigurationModel model, ClassLoader classLoader) {
public ConfigurationClassVisitor(ConfigurationClass configClass, ConfigurationModel model,
ProblemReporter problemReporter, ClassLoader classLoader) {
super(AsmUtils.EMPTY_VISITOR);
this.configClass = configClass;
this.model = model;
this.problemReporter = problemReporter;
this.classLoader = classLoader;
}
......@@ -86,7 +96,8 @@ class ConfigurationClassVisitor extends ClassAdapter {
if (OBJECT_DESC.equals(superTypeDesc))
return;
ConfigurationClassVisitor visitor = new ConfigurationClassVisitor(configClass, model, classLoader);
ConfigurationClassVisitor visitor =
new ConfigurationClassVisitor(configClass, model, problemReporter, classLoader);
ClassReader reader = AsmUtils.newClassReader(superTypeDesc, classLoader);
reader.accept(visitor, false);
......@@ -116,12 +127,15 @@ class ConfigurationClassVisitor extends ClassAdapter {
if (Import.class.getName().equals(annoTypeName)) {
ImportStack importStack = ImportStackHolder.getImportStack();
if (importStack.contains(configClass))
throw new CircularImportException(configClass, importStack);
if (importStack.contains(configClass)) {
//throw new CircularImportException(configClass, importStack);
problemReporter.error(new CircularImportProblem(configClass, importStack));
return new EmptyVisitor();
}
importStack.push(configClass);
return new ImportAnnotationVisitor(model, classLoader);
return new ImportAnnotationVisitor(model, problemReporter, classLoader);
}
/* -------------------------------------
......@@ -217,7 +231,7 @@ class ConfigurationClassVisitor extends ClassAdapter {
ConfigurationClass innerConfigClass = new ConfigurationClass();
ConfigurationClassVisitor ccVisitor =
new ConfigurationClassVisitor(innerConfigClass, new ConfigurationModel(), classLoader);
new ConfigurationClassVisitor(innerConfigClass, new ConfigurationModel(), problemReporter, classLoader);
ccVisitor.setProcessInnerClasses(false);
ClassReader reader = AsmUtils.newClassReader(name, classLoader);
......@@ -230,4 +244,27 @@ class ConfigurationClassVisitor extends ClassAdapter {
if (innerConfigClass.getMetadata() != null)
innerClasses.put(name, innerConfigClass);
}
/**
* {@link Problem} registered upon detection of a circular {@link Import}.
*
* @see Import
* @see ImportStack
* @see ImportStackHolder
*/
class CircularImportProblem extends Problem {
public CircularImportProblem(ConfigurationClass attemptedImport, Stack<ConfigurationClass> currentImportStack) {
super(format("A circular @Import has been detected: " +
"Illegal attempt by @Configuration class '%s' to import class '%s' as '%s' is " +
"already present in the current import stack [%s]",
currentImportStack.peek().getSimpleName(), attemptedImport.getSimpleName(),
attemptedImport.getSimpleName(), currentImportStack),
new Location(new FileSystemResource("/dev/null"))
);
}
}
}
......@@ -17,6 +17,7 @@ package org.springframework.config.java.support;
import org.springframework.asm.ClassReader;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.parsing.ProblemReporter;
import org.springframework.config.java.Configuration;
import org.springframework.util.ClassUtils;
......@@ -41,17 +42,18 @@ public class ConfigurationParser {
* Model to be populated during calls to {@link #parse(Object, String)}
*/
private final ConfigurationModel model;
private final ProblemReporter problemReporter;
private final ClassLoader classLoader;
/**
* Creates a new parser instance that will be used to populate <var>model</var>.
*
* @param model model to be populated by each successive call to
* {@link #parse(Object, String)}
*/
public ConfigurationParser(ClassLoader classLoader) {
this.classLoader = classLoader;
public ConfigurationParser(ProblemReporter problemReporter, ClassLoader classLoader) {
this.model = new ConfigurationModel();
this.problemReporter = problemReporter;
this.classLoader = classLoader;
}
/**
......@@ -71,7 +73,7 @@ public class ConfigurationParser {
ConfigurationClass configClass = new ConfigurationClass();
configClass.setBeanName(configurationId);
configClassReader.accept(new ConfigurationClassVisitor(configClass, model, classLoader), false);
configClassReader.accept(new ConfigurationClassVisitor(configClass, model, problemReporter, classLoader), false);
model.add(configClass);
}
......
......@@ -24,6 +24,7 @@ import java.util.ArrayList;
import org.springframework.asm.AnnotationVisitor;
import org.springframework.asm.ClassReader;
import org.springframework.asm.Type;
import org.springframework.beans.factory.parsing.ProblemReporter;
import org.springframework.config.java.Import;
import org.springframework.util.Assert;
......@@ -42,11 +43,13 @@ import org.springframework.util.Assert;
class ImportAnnotationVisitor extends AnnotationAdapter {
private final ArrayList<String> classesToImport = new ArrayList<String>();
private final ConfigurationModel model;
private final ProblemReporter problemReporter;
private final ClassLoader classLoader;
public ImportAnnotationVisitor(ConfigurationModel model, ClassLoader classLoader) {
public ImportAnnotationVisitor(ConfigurationModel model, ProblemReporter problemReporter, ClassLoader classLoader) {
super(AsmUtils.EMPTY_VISITOR);
this.model = model;
this.problemReporter = problemReporter;
this.classLoader = classLoader;
}
......@@ -77,7 +80,7 @@ class ImportAnnotationVisitor extends AnnotationAdapter {
ClassReader reader = newClassReader(convertClassNameToResourcePath(classToImport), classLoader);
reader.accept(new ConfigurationClassVisitor(configClass, model, classLoader), false);
reader.accept(new ConfigurationClassVisitor(configClass, model, problemReporter, classLoader), false);
model.add(configClass);
}
......
......@@ -18,6 +18,7 @@ package org.springframework.config.java.support;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
import org.springframework.config.java.Bean;
import org.springframework.config.java.Import;
......@@ -40,7 +41,7 @@ public abstract class AbstractCircularImportDetectionTests {
boolean threw = false;
try {
newParser().parse(loadAsConfigurationSource(A.class), null);
} catch (CircularImportException ex) {
} catch (BeanDefinitionParsingException ex) {
assertTrue("Wrong message. Got: " + ex.getMessage(),
ex.getMessage().contains(
"Illegal attempt by @Configuration class 'AbstractCircularImportDetectionTests.B' " +
......@@ -57,7 +58,7 @@ public abstract class AbstractCircularImportDetectionTests {
boolean threw = false;
try {
newParser().parse(loadAsConfigurationSource(X.class), null);
} catch (CircularImportException ex) {
} catch (BeanDefinitionParsingException ex) {
assertTrue("Wrong message. Got: " + ex.getMessage(),
ex.getMessage().contains(
"Illegal attempt by @Configuration class 'AbstractCircularImportDetectionTests.Z2' " +
......
......@@ -15,6 +15,7 @@
*/
package org.springframework.config.java.support;
import org.springframework.beans.factory.parsing.FailFastProblemReporter;
import org.springframework.config.java.Import;
import org.springframework.util.ClassUtils;
......@@ -32,7 +33,7 @@ import org.springframework.util.ClassUtils;
public class AsmCircularImportDetectionTests extends AbstractCircularImportDetectionTests {
@Override
protected ConfigurationParser newParser() {
return new ConfigurationParser(ClassUtils.getDefaultClassLoader());
return new ConfigurationParser(new FailFastProblemReporter(), ClassUtils.getDefaultClassLoader());
}
@Override
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册