+ Adding POC tooling integration points, namely AbstractConfigurationPostProcessor and allowing for tooling-specified ClassLoader for use with ASM parsing
+ Eliminated ModelMethod in favor of BeanMethod throughout
This commit is contained in:
parent
61a1c4d0c6
commit
eaf3a7cec4
|
@ -13,7 +13,7 @@ import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||||
* declare a no-arg constructor.
|
* declare a no-arg constructor.
|
||||||
*
|
*
|
||||||
* @see FactoryMethod
|
* @see FactoryMethod
|
||||||
* @see ModelMethod
|
* @see BeanMethod
|
||||||
*
|
*
|
||||||
* @author Chris Beams
|
* @author Chris Beams
|
||||||
*/
|
*/
|
||||||
|
@ -31,6 +31,6 @@ public interface BeanDefinitionRegistrar {
|
||||||
/**
|
/**
|
||||||
* Registers any bean definitions for <var>method</var> with <var>registry</var>.
|
* Registers any bean definitions for <var>method</var> with <var>registry</var>.
|
||||||
*/
|
*/
|
||||||
void register(ModelMethod method, BeanDefinitionRegistry registry);
|
void register(BeanMethod method, BeanDefinitionRegistry registry);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
|
||||||
/** TODO: JAVADOC */
|
/** TODO: JAVADOC */
|
||||||
public final class ModelMethod implements Validatable {
|
public final class BeanMethod implements Validatable {
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
private final int modifiers;
|
private final int modifiers;
|
||||||
|
@ -42,7 +42,7 @@ public final class ModelMethod implements Validatable {
|
||||||
private transient FactoryMethod factoryAnno;
|
private transient FactoryMethod factoryAnno;
|
||||||
private transient final List<Validator> validators = new ArrayList<Validator>();
|
private transient final List<Validator> validators = new ArrayList<Validator>();
|
||||||
|
|
||||||
public ModelMethod(String name, int modifiers, ModelClass returnType, Annotation... annotations) {
|
public BeanMethod(String name, int modifiers, ModelClass returnType, Annotation... annotations) {
|
||||||
Assert.hasText(name);
|
Assert.hasText(name);
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ public final class ModelMethod implements Validatable {
|
||||||
/**
|
/**
|
||||||
* Sets up bi-directional relationship between this method and its declaring class.
|
* Sets up bi-directional relationship between this method and its declaring class.
|
||||||
*
|
*
|
||||||
* @see ConfigurationClass#addMethod(ModelMethod)
|
* @see ConfigurationClass#addMethod(BeanMethod)
|
||||||
*/
|
*/
|
||||||
public void setDeclaringClass(ConfigurationClass declaringClass) {
|
public void setDeclaringClass(ConfigurationClass declaringClass) {
|
||||||
this.declaringClass = declaringClass;
|
this.declaringClass = declaringClass;
|
||||||
|
@ -132,8 +132,8 @@ public final class ModelMethod implements Validatable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void validate(List<UsageError> errors) {
|
public void validate(List<UsageError> errors) {
|
||||||
for (Validator validator : validators)
|
// for (Validator validator : validators)
|
||||||
validator.validate(this, errors);
|
// validator.validate(this, errors);
|
||||||
|
|
||||||
if (Modifier.isPrivate(getModifiers()))
|
if (Modifier.isPrivate(getModifiers()))
|
||||||
errors.add(new PrivateMethodError());
|
errors.add(new PrivateMethodError());
|
||||||
|
@ -190,7 +190,7 @@ public final class ModelMethod implements Validatable {
|
||||||
return false;
|
return false;
|
||||||
if (getClass() != obj.getClass())
|
if (getClass() != obj.getClass())
|
||||||
return false;
|
return false;
|
||||||
ModelMethod other = (ModelMethod) obj;
|
BeanMethod other = (BeanMethod) obj;
|
||||||
if (annotations == null) {
|
if (annotations == null) {
|
||||||
if (other.annotations != null)
|
if (other.annotations != null)
|
||||||
return false;
|
return false;
|
|
@ -24,6 +24,7 @@ import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.springframework.config.java.ext.Bean;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
import sun.security.x509.Extension;
|
import sun.security.x509.Extension;
|
||||||
|
@ -55,7 +56,7 @@ public final class ConfigurationClass extends ModelClass implements Validatable
|
||||||
|
|
||||||
private Configuration metadata;
|
private Configuration metadata;
|
||||||
|
|
||||||
private HashSet<ModelMethod> methods = new HashSet<ModelMethod>();
|
private HashSet<BeanMethod> methods = new HashSet<BeanMethod>();
|
||||||
|
|
||||||
private HashSet<Annotation> pluginAnnotations = new HashSet<Annotation>();
|
private HashSet<Annotation> pluginAnnotations = new HashSet<Annotation>();
|
||||||
|
|
||||||
|
@ -112,7 +113,7 @@ public final class ConfigurationClass extends ModelClass implements Validatable
|
||||||
setModifiers(modifiers);
|
setModifiers(modifiers);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConfigurationClass addMethod(ModelMethod method) {
|
public ConfigurationClass addMethod(BeanMethod method) {
|
||||||
method.setDeclaringClass(this);
|
method.setDeclaringClass(this);
|
||||||
methods.add(method);
|
methods.add(method);
|
||||||
return this;
|
return this;
|
||||||
|
@ -127,7 +128,7 @@ public final class ConfigurationClass extends ModelClass implements Validatable
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<ModelMethod> getMethods() {
|
public Set<BeanMethod> getMethods() {
|
||||||
return methods;
|
return methods;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,7 +185,7 @@ public final class ConfigurationClass extends ModelClass implements Validatable
|
||||||
if (Modifier.isFinal(modifiers))
|
if (Modifier.isFinal(modifiers))
|
||||||
errors.add(new FinalConfigurationError());
|
errors.add(new FinalConfigurationError());
|
||||||
|
|
||||||
for (ModelMethod method : methods)
|
for (BeanMethod method : methods)
|
||||||
method.validate(errors);
|
method.validate(errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -299,7 +300,7 @@ public final class ConfigurationClass extends ModelClass implements Validatable
|
||||||
*/
|
*/
|
||||||
public class IllegalBeanOverrideError extends UsageError {
|
public class IllegalBeanOverrideError extends UsageError {
|
||||||
private final ConfigurationClass authoritativeClass;
|
private final ConfigurationClass authoritativeClass;
|
||||||
private final ModelMethod finalMethodInQuestion;
|
private final BeanMethod finalMethodInQuestion;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new IllegalBeanOverrideError object.
|
* Creates a new IllegalBeanOverrideError object.
|
||||||
|
@ -310,7 +311,7 @@ public final class ConfigurationClass extends ModelClass implements Validatable
|
||||||
* @param finalMethodInQuestion the method that has been marked
|
* @param finalMethodInQuestion the method that has been marked
|
||||||
* 'allowOverriding=false'
|
* 'allowOverriding=false'
|
||||||
*/
|
*/
|
||||||
public IllegalBeanOverrideError(ConfigurationClass violatingClass, ModelMethod finalMethodInQuestion) {
|
public IllegalBeanOverrideError(ConfigurationClass violatingClass, BeanMethod finalMethodInQuestion) {
|
||||||
super(violatingClass, -1);
|
super(violatingClass, -1);
|
||||||
this.authoritativeClass = ConfigurationClass.this;
|
this.authoritativeClass = ConfigurationClass.this;
|
||||||
this.finalMethodInQuestion = finalMethodInQuestion;
|
this.finalMethodInQuestion = finalMethodInQuestion;
|
||||||
|
@ -329,9 +330,9 @@ public final class ConfigurationClass extends ModelClass implements Validatable
|
||||||
return getMethod(methodName) != null;
|
return getMethod(methodName) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ModelMethod getMethod(String methodName) {
|
public BeanMethod getMethod(String methodName) {
|
||||||
|
|
||||||
for (ModelMethod method : methods)
|
for (BeanMethod method : methods)
|
||||||
if (methodName.equals(method.getName()))
|
if (methodName.equals(method.getName()))
|
||||||
return method;
|
return method;
|
||||||
|
|
||||||
|
|
|
@ -94,7 +94,7 @@ public final class ConfigurationModel implements Validatable {
|
||||||
* <var>errors</var>.
|
* <var>errors</var>.
|
||||||
*
|
*
|
||||||
* @see ConfigurationClass#validate(java.util.List)
|
* @see ConfigurationClass#validate(java.util.List)
|
||||||
* @see ModelMethod#validate(java.util.List)
|
* @see BeanMethod#validate(java.util.List)
|
||||||
* @see Validator
|
* @see Validator
|
||||||
* @see UsageError
|
* @see UsageError
|
||||||
*/
|
*/
|
||||||
|
@ -107,7 +107,7 @@ public final class ConfigurationModel implements Validatable {
|
||||||
// depending on where they are registered (with the model, the class, or the method)
|
// depending on where they are registered (with the model, the class, or the method)
|
||||||
// they will be called directly or indirectly below
|
// they will be called directly or indirectly below
|
||||||
for (ConfigurationClass configClass : getAllConfigurationClasses()) {
|
for (ConfigurationClass configClass : getAllConfigurationClasses()) {
|
||||||
for (ModelMethod method : configClass.getMethods()) {
|
for (BeanMethod method : configClass.getMethods()) {
|
||||||
for (Validator validator : method.getValidators()) {
|
for (Validator validator : method.getValidators()) {
|
||||||
if (validator.supports(method))
|
if (validator.supports(method))
|
||||||
method.registerValidator(validator);
|
method.registerValidator(validator);
|
||||||
|
|
|
@ -98,6 +98,7 @@ public class ModelClass implements BeanMetadataElement {
|
||||||
* Returns a resource path-formatted representation of the .java file that declares this
|
* Returns a resource path-formatted representation of the .java file that declares this
|
||||||
* class
|
* class
|
||||||
*/
|
*/
|
||||||
|
// TODO: return type should be Object here. Spring IDE will return a JDT representation...
|
||||||
public String getSource() {
|
public String getSource() {
|
||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,9 +131,9 @@ public class Util {
|
||||||
* @see ClassUtils#getDefaultClassLoader()
|
* @see ClassUtils#getDefaultClassLoader()
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static <T> Class<? extends T> loadToolingSafeClass(String fqClassName) {
|
public static <T> Class<? extends T> loadToolingSafeClass(String fqClassName, ClassLoader classLoader) {
|
||||||
try {
|
try {
|
||||||
return (Class<? extends T>) ClassUtils.getDefaultClassLoader().loadClass(fqClassName);
|
return (Class<? extends T>) classLoader.loadClass(fqClassName);
|
||||||
} catch (ClassNotFoundException ex) {
|
} catch (ClassNotFoundException ex) {
|
||||||
log.warn(format("Unable to load class [%s], likely due to tooling-specific restrictions."
|
log.warn(format("Unable to load class [%s], likely due to tooling-specific restrictions."
|
||||||
+ "Attempting to continue, but unexpected errors may occur", fqClassName), ex);
|
+ "Attempting to continue, but unexpected errors may occur", fqClassName), ex);
|
||||||
|
@ -152,10 +152,10 @@ public class Util {
|
||||||
*
|
*
|
||||||
* @throws RuntimeException if <var>pathToClass</var> does not exist
|
* @throws RuntimeException if <var>pathToClass</var> does not exist
|
||||||
*/
|
*/
|
||||||
public static InputStream getClassAsStream(String pathToClass) {
|
public static InputStream getClassAsStream(String pathToClass, ClassLoader classLoader) {
|
||||||
String classFileName = pathToClass + ClassUtils.CLASS_FILE_SUFFIX;
|
String classFileName = pathToClass + ClassUtils.CLASS_FILE_SUFFIX;
|
||||||
|
|
||||||
InputStream is = ClassUtils.getDefaultClassLoader().getResourceAsStream(classFileName);
|
InputStream is = classLoader.getResourceAsStream(classFileName);
|
||||||
|
|
||||||
if (is == null)
|
if (is == null)
|
||||||
throw new RuntimeException(new FileNotFoundException("Class file [" + classFileName
|
throw new RuntimeException(new FileNotFoundException("Class file [" + classFileName
|
||||||
|
|
|
@ -26,11 +26,11 @@ import java.util.List;
|
||||||
import org.springframework.beans.factory.annotation.Autowire;
|
import org.springframework.beans.factory.annotation.Autowire;
|
||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||||
|
import org.springframework.config.java.BeanMethod;
|
||||||
import org.springframework.config.java.Configuration;
|
import org.springframework.config.java.Configuration;
|
||||||
import org.springframework.config.java.ConfigurationClass;
|
import org.springframework.config.java.ConfigurationClass;
|
||||||
import org.springframework.config.java.ConfigurationModel;
|
import org.springframework.config.java.ConfigurationModel;
|
||||||
import org.springframework.config.java.FactoryMethod;
|
import org.springframework.config.java.FactoryMethod;
|
||||||
import org.springframework.config.java.ModelMethod;
|
|
||||||
import org.springframework.config.java.Scopes;
|
import org.springframework.config.java.Scopes;
|
||||||
import org.springframework.config.java.UsageError;
|
import org.springframework.config.java.UsageError;
|
||||||
import org.springframework.config.java.Validator;
|
import org.springframework.config.java.Validator;
|
||||||
|
@ -164,11 +164,11 @@ public @interface Bean {
|
||||||
class BeanValidator implements Validator {
|
class BeanValidator implements Validator {
|
||||||
|
|
||||||
public boolean supports(Object object) {
|
public boolean supports(Object object) {
|
||||||
return object instanceof ModelMethod;
|
return object instanceof BeanMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void validate(Object object, List<UsageError> errors) {
|
public void validate(Object object, List<UsageError> errors) {
|
||||||
ModelMethod method = (ModelMethod) object;
|
BeanMethod method = (BeanMethod) object;
|
||||||
|
|
||||||
// TODO: re-enable for @ScopedProxy support
|
// TODO: re-enable for @ScopedProxy support
|
||||||
// if (method.getAnnotation(ScopedProxy.class) == null)
|
// if (method.getAnnotation(ScopedProxy.class) == null)
|
||||||
|
@ -204,7 +204,7 @@ class IllegalBeanOverrideValidator implements Validator {
|
||||||
ConfigurationClass[] allClasses = model.getAllConfigurationClasses();
|
ConfigurationClass[] allClasses = model.getAllConfigurationClasses();
|
||||||
|
|
||||||
for (int i = 0; i < allClasses.length; i++) {
|
for (int i = 0; i < allClasses.length; i++) {
|
||||||
for (ModelMethod method : allClasses[i].getMethods()) {
|
for (BeanMethod method : allClasses[i].getMethods()) {
|
||||||
Bean bean = method.getAnnotation(Bean.class);
|
Bean bean = method.getAnnotation(Bean.class);
|
||||||
|
|
||||||
if (bean == null || bean.allowOverriding())
|
if (bean == null || bean.allowOverriding())
|
||||||
|
|
|
@ -33,7 +33,7 @@ import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||||
*
|
*
|
||||||
* @author Chris Beams
|
* @author Chris Beams
|
||||||
*/
|
*/
|
||||||
class BeanMethodInterceptor extends AbstractMethodInterceptor {
|
public class BeanMethodInterceptor extends AbstractMethodInterceptor {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enhances a {@link Bean @Bean} method to check the supplied BeanFactory for the
|
* Enhances a {@link Bean @Bean} method to check the supplied BeanFactory for the
|
||||||
|
|
|
@ -14,18 +14,17 @@ import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||||
import org.springframework.config.java.BeanDefinitionRegistrar;
|
import org.springframework.config.java.BeanDefinitionRegistrar;
|
||||||
|
import org.springframework.config.java.BeanMethod;
|
||||||
import org.springframework.config.java.Configuration;
|
import org.springframework.config.java.Configuration;
|
||||||
import org.springframework.config.java.ConfigurationClass;
|
import org.springframework.config.java.ConfigurationClass;
|
||||||
import org.springframework.config.java.MalformedConfigurationException;
|
import org.springframework.config.java.MalformedConfigurationException;
|
||||||
import org.springframework.config.java.ModelMethod;
|
|
||||||
import org.springframework.config.java.UsageError;
|
import org.springframework.config.java.UsageError;
|
||||||
import org.springframework.core.annotation.AnnotationUtils;
|
import org.springframework.core.annotation.AnnotationUtils;
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: SJC-242 document BeanHandler
|
// TODO: SJC-242 document BeanHandler
|
||||||
// TODO: SJC-242 make package-private
|
// TODO: SJC-242 make package-private
|
||||||
class BeanRegistrar implements BeanDefinitionRegistrar {
|
public class BeanRegistrar implements BeanDefinitionRegistrar {
|
||||||
|
|
||||||
private static final Log logger = LogFactory.getLog(BeanRegistrar.class);
|
private static final Log logger = LogFactory.getLog(BeanRegistrar.class);
|
||||||
|
|
||||||
|
@ -38,7 +37,7 @@ class BeanRegistrar implements BeanDefinitionRegistrar {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: SJC-242 method too long
|
// TODO: SJC-242 method too long
|
||||||
public void register(ModelMethod method, BeanDefinitionRegistry registry) {
|
public void register(BeanMethod method, BeanDefinitionRegistry registry) {
|
||||||
RootBeanDefinition beanDef = new ConfigurationClassBeanDefinition();
|
RootBeanDefinition beanDef = new ConfigurationClassBeanDefinition();
|
||||||
|
|
||||||
ConfigurationClass configClass = method.getDeclaringClass();
|
ConfigurationClass configClass = method.getDeclaringClass();
|
||||||
|
@ -171,7 +170,10 @@ class BeanRegistrar implements BeanDefinitionRegistrar {
|
||||||
}
|
}
|
||||||
|
|
||||||
private BeanDefinition getBeanDefinitionIncludingAncestry(String beanName, BeanDefinitionRegistry registry) {
|
private BeanDefinition getBeanDefinitionIncludingAncestry(String beanName, BeanDefinitionRegistry registry) {
|
||||||
Assert.isInstanceOf(ConfigurableListableBeanFactory.class, registry);
|
if(!(registry instanceof ConfigurableListableBeanFactory)) {
|
||||||
|
return registry.getBeanDefinition(beanName);
|
||||||
|
}
|
||||||
|
|
||||||
ConfigurableListableBeanFactory clbf = (ConfigurableListableBeanFactory) registry;
|
ConfigurableListableBeanFactory clbf = (ConfigurableListableBeanFactory) registry;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
|
|
@ -39,11 +39,13 @@ import org.springframework.beans.factory.BeanFactoryAware;
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||||
import org.springframework.config.java.BeanDefinitionRegistrar;
|
import org.springframework.config.java.BeanDefinitionRegistrar;
|
||||||
|
import org.springframework.config.java.BeanMethod;
|
||||||
import org.springframework.config.java.Configuration;
|
import org.springframework.config.java.Configuration;
|
||||||
import org.springframework.config.java.ConfigurationClass;
|
import org.springframework.config.java.ConfigurationClass;
|
||||||
import org.springframework.config.java.ConfigurationModel;
|
import org.springframework.config.java.ConfigurationModel;
|
||||||
import org.springframework.config.java.ModelMethod;
|
|
||||||
import org.springframework.config.java.NoOpInterceptor;
|
import org.springframework.config.java.NoOpInterceptor;
|
||||||
|
import org.springframework.config.java.ext.BeanMethodInterceptor;
|
||||||
|
import org.springframework.config.java.ext.BeanRegistrar;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -81,11 +83,31 @@ public class ConfigurationEnhancer {
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link ConfigurationEnhancer} instance.
|
* Creates a new {@link ConfigurationEnhancer} instance.
|
||||||
*/
|
*/
|
||||||
public ConfigurationEnhancer(DefaultListableBeanFactory beanFactory, ConfigurationModel model) {
|
public ConfigurationEnhancer(DefaultListableBeanFactory beanFactory) {
|
||||||
notNull(beanFactory, "beanFactory must be non-null");
|
notNull(beanFactory, "beanFactory must be non-null");
|
||||||
notNull(model, "model must be non-null");
|
//notNull(model, "model must be non-null");
|
||||||
|
|
||||||
populateRegistrarsAndCallbacks(beanFactory, model);
|
//populateRegistrarsAndCallbacks(beanFactory, model);
|
||||||
|
|
||||||
|
registrars.add(new BeanRegistrar());
|
||||||
|
BeanMethodInterceptor beanMethodInterceptor = new BeanMethodInterceptor();
|
||||||
|
beanMethodInterceptor.setBeanFactory(beanFactory);
|
||||||
|
callbackInstances.add(beanMethodInterceptor);
|
||||||
|
|
||||||
|
registrars.add(new BeanDefinitionRegistrar() {
|
||||||
|
|
||||||
|
public boolean accepts(Method method) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void register(BeanMethod method, BeanDefinitionRegistry registry) {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
});
|
||||||
|
callbackInstances.add(NoOpInterceptor.INSTANCE);
|
||||||
|
|
||||||
|
for (Callback callback : callbackInstances)
|
||||||
|
callbackTypes.add(callback.getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -97,9 +119,9 @@ public class ConfigurationEnhancer {
|
||||||
*/
|
*/
|
||||||
private void populateRegistrarsAndCallbacks(DefaultListableBeanFactory beanFactory,
|
private void populateRegistrarsAndCallbacks(DefaultListableBeanFactory beanFactory,
|
||||||
ConfigurationModel model) {
|
ConfigurationModel model) {
|
||||||
|
|
||||||
for (ConfigurationClass configClass : model.getAllConfigurationClasses()) {
|
for (ConfigurationClass configClass : model.getAllConfigurationClasses()) {
|
||||||
for (ModelMethod method : configClass.getMethods()) {
|
for (BeanMethod method : configClass.getMethods()) {
|
||||||
registrars.add(method.getRegistrar());
|
registrars.add(method.getRegistrar());
|
||||||
|
|
||||||
Callback callback = method.getCallback();
|
Callback callback = method.getCallback();
|
||||||
|
@ -118,7 +140,7 @@ public class ConfigurationEnhancer {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void register(ModelMethod method, BeanDefinitionRegistry registry) {
|
public void register(BeanMethod method, BeanDefinitionRegistry registry) {
|
||||||
// no-op
|
// no-op
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -97,8 +97,8 @@ class AsmUtils {
|
||||||
* classpath
|
* classpath
|
||||||
* @throws RuntimeException if an IOException occurs when creating the new ClassReader
|
* @throws RuntimeException if an IOException occurs when creating the new ClassReader
|
||||||
*/
|
*/
|
||||||
public static ClassReader newClassReader(String pathToClass) {
|
public static ClassReader newClassReader(String pathToClass, ClassLoader classLoader) {
|
||||||
InputStream is = Util.getClassAsStream(pathToClass);
|
InputStream is = Util.getClassAsStream(pathToClass, classLoader);
|
||||||
return newClassReader(is);
|
return newClassReader(is);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,11 +28,12 @@ import org.objectweb.asm.ClassAdapter;
|
||||||
import org.objectweb.asm.Label;
|
import org.objectweb.asm.Label;
|
||||||
import org.objectweb.asm.MethodAdapter;
|
import org.objectweb.asm.MethodAdapter;
|
||||||
import org.objectweb.asm.Opcodes;
|
import org.objectweb.asm.Opcodes;
|
||||||
|
import org.springframework.config.java.BeanMethod;
|
||||||
import org.springframework.config.java.Configuration;
|
import org.springframework.config.java.Configuration;
|
||||||
import org.springframework.config.java.ConfigurationClass;
|
import org.springframework.config.java.ConfigurationClass;
|
||||||
import org.springframework.config.java.FactoryMethod;
|
import org.springframework.config.java.FactoryMethod;
|
||||||
import org.springframework.config.java.ModelClass;
|
import org.springframework.config.java.ModelClass;
|
||||||
import org.springframework.config.java.ModelMethod;
|
import org.springframework.config.java.ext.Bean;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -49,6 +50,7 @@ class ConfigurationClassMethodVisitor extends MethodAdapter {
|
||||||
private final int modifiers;
|
private final int modifiers;
|
||||||
private final ModelClass returnType;
|
private final ModelClass returnType;
|
||||||
private final ArrayList<Annotation> annotations = new ArrayList<Annotation>();
|
private final ArrayList<Annotation> annotations = new ArrayList<Annotation>();
|
||||||
|
private final ClassLoader classLoader;
|
||||||
|
|
||||||
private boolean isModelMethod = false;
|
private boolean isModelMethod = false;
|
||||||
private int lineNumber;
|
private int lineNumber;
|
||||||
|
@ -62,13 +64,14 @@ class ConfigurationClassMethodVisitor extends MethodAdapter {
|
||||||
* @param modifiers modifiers for this method
|
* @param modifiers modifiers for this method
|
||||||
*/
|
*/
|
||||||
public ConfigurationClassMethodVisitor(ConfigurationClass configClass, String methodName,
|
public ConfigurationClassMethodVisitor(ConfigurationClass configClass, String methodName,
|
||||||
String methodDescriptor, int modifiers) {
|
String methodDescriptor, int modifiers, ClassLoader classLoader) {
|
||||||
super(AsmUtils.EMPTY_VISITOR);
|
super(AsmUtils.EMPTY_VISITOR);
|
||||||
|
|
||||||
this.configClass = configClass;
|
this.configClass = configClass;
|
||||||
this.methodName = methodName;
|
this.methodName = methodName;
|
||||||
this.returnType = initReturnTypeFromMethodDescriptor(methodDescriptor);
|
this.classLoader = classLoader;
|
||||||
this.modifiers = modifiers;
|
this.modifiers = modifiers;
|
||||||
|
this.returnType = initReturnTypeFromMethodDescriptor(methodDescriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -79,7 +82,7 @@ class ConfigurationClassMethodVisitor extends MethodAdapter {
|
||||||
public AnnotationVisitor visitAnnotation(String annoTypeDesc, boolean visible) {
|
public AnnotationVisitor visitAnnotation(String annoTypeDesc, boolean visible) {
|
||||||
String annoClassName = AsmUtils.convertTypeDescriptorToClassName(annoTypeDesc);
|
String annoClassName = AsmUtils.convertTypeDescriptorToClassName(annoTypeDesc);
|
||||||
|
|
||||||
Class<? extends Annotation> annoClass = loadToolingSafeClass(annoClassName);
|
Class<? extends Annotation> annoClass = loadToolingSafeClass(annoClassName, classLoader);
|
||||||
|
|
||||||
if (annoClass == null)
|
if (annoClass == null)
|
||||||
return super.visitAnnotation(annoTypeDesc, visible);
|
return super.visitAnnotation(annoTypeDesc, visible);
|
||||||
|
@ -88,7 +91,7 @@ class ConfigurationClassMethodVisitor extends MethodAdapter {
|
||||||
|
|
||||||
annotations.add(annotation);
|
annotations.add(annotation);
|
||||||
|
|
||||||
return new MutableAnnotationVisitor(annotation);
|
return new MutableAnnotationVisitor(annotation, classLoader);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -111,7 +114,7 @@ class ConfigurationClassMethodVisitor extends MethodAdapter {
|
||||||
@Override
|
@Override
|
||||||
public void visitEnd() {
|
public void visitEnd() {
|
||||||
for (Annotation anno : annotations) {
|
for (Annotation anno : annotations) {
|
||||||
if (anno.annotationType().getAnnotation(FactoryMethod.class) != null) {
|
if (anno.annotationType().equals(Bean.class)) {
|
||||||
isModelMethod = true;
|
isModelMethod = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -121,7 +124,7 @@ class ConfigurationClassMethodVisitor extends MethodAdapter {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Annotation[] annoArray = annotations.toArray(new Annotation[] {});
|
Annotation[] annoArray = annotations.toArray(new Annotation[] {});
|
||||||
ModelMethod method = new ModelMethod(methodName, modifiers, returnType, annoArray);
|
BeanMethod method = new BeanMethod(methodName, modifiers, returnType, annoArray);
|
||||||
method.setLineNumber(lineNumber);
|
method.setLineNumber(lineNumber);
|
||||||
configClass.addMethod(method);
|
configClass.addMethod(method);
|
||||||
}
|
}
|
||||||
|
@ -130,11 +133,11 @@ class ConfigurationClassMethodVisitor extends MethodAdapter {
|
||||||
* Determines return type from ASM <var>methodDescriptor</var> and determines whether
|
* Determines return type from ASM <var>methodDescriptor</var> and determines whether
|
||||||
* that type is an interface.
|
* that type is an interface.
|
||||||
*/
|
*/
|
||||||
private static ModelClass initReturnTypeFromMethodDescriptor(String methodDescriptor) {
|
private ModelClass initReturnTypeFromMethodDescriptor(String methodDescriptor) {
|
||||||
final ModelClass returnType = new ModelClass(getReturnTypeFromMethodDescriptor(methodDescriptor));
|
final ModelClass returnType = new ModelClass(getReturnTypeFromMethodDescriptor(methodDescriptor));
|
||||||
|
|
||||||
// detect whether the return type is an interface
|
// detect whether the return type is an interface
|
||||||
newClassReader(convertClassNameToResourcePath(returnType.getName())).accept(
|
newClassReader(convertClassNameToResourcePath(returnType.getName()), classLoader).accept(
|
||||||
new ClassAdapter(AsmUtils.EMPTY_VISITOR) {
|
new ClassAdapter(AsmUtils.EMPTY_VISITOR) {
|
||||||
@Override
|
@Override
|
||||||
public void visit(int arg0, int arg1, String arg2, String arg3, String arg4, String[] arg5) {
|
public void visit(int arg0, int arg1, String arg2, String arg3, String arg4, String[] arg5) {
|
||||||
|
|
|
@ -52,11 +52,13 @@ class ConfigurationClassVisitor extends ClassAdapter {
|
||||||
private final HashMap<String, ConfigurationClass> innerClasses = new HashMap<String, ConfigurationClass>();
|
private final HashMap<String, ConfigurationClass> innerClasses = new HashMap<String, ConfigurationClass>();
|
||||||
|
|
||||||
private boolean processInnerClasses = true;
|
private boolean processInnerClasses = true;
|
||||||
|
private final ClassLoader classLoader;
|
||||||
|
|
||||||
public ConfigurationClassVisitor(ConfigurationClass configClass, ConfigurationModel model) {
|
public ConfigurationClassVisitor(ConfigurationClass configClass, ConfigurationModel model, ClassLoader classLoader) {
|
||||||
super(AsmUtils.EMPTY_VISITOR);
|
super(AsmUtils.EMPTY_VISITOR);
|
||||||
this.configClass = configClass;
|
this.configClass = configClass;
|
||||||
this.model = model;
|
this.model = model;
|
||||||
|
this.classLoader = classLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setProcessInnerClasses(boolean processInnerClasses) {
|
public void setProcessInnerClasses(boolean processInnerClasses) {
|
||||||
|
@ -89,9 +91,9 @@ class ConfigurationClassVisitor extends ClassAdapter {
|
||||||
if (OBJECT_DESC.equals(superTypeDesc))
|
if (OBJECT_DESC.equals(superTypeDesc))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ConfigurationClassVisitor visitor = new ConfigurationClassVisitor(configClass, model);
|
ConfigurationClassVisitor visitor = new ConfigurationClassVisitor(configClass, model, classLoader);
|
||||||
|
|
||||||
ClassReader reader = AsmUtils.newClassReader(superTypeDesc);
|
ClassReader reader = AsmUtils.newClassReader(superTypeDesc, classLoader);
|
||||||
reader.accept(visitor, false);
|
reader.accept(visitor, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,7 +115,7 @@ class ConfigurationClassVisitor extends ClassAdapter {
|
||||||
if (Configuration.class.getName().equals(annoTypeName)) {
|
if (Configuration.class.getName().equals(annoTypeName)) {
|
||||||
Configuration mutableConfiguration = createMutableAnnotation(Configuration.class);
|
Configuration mutableConfiguration = createMutableAnnotation(Configuration.class);
|
||||||
configClass.setMetadata(mutableConfiguration);
|
configClass.setMetadata(mutableConfiguration);
|
||||||
return new MutableAnnotationVisitor(mutableConfiguration);
|
return new MutableAnnotationVisitor(mutableConfiguration, classLoader);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: re-enable for @Import support
|
// TODO: re-enable for @Import support
|
||||||
|
@ -131,39 +133,41 @@ class ConfigurationClassVisitor extends ClassAdapter {
|
||||||
// -------------------------------------
|
// -------------------------------------
|
||||||
// Detect @Plugin annotations
|
// Detect @Plugin annotations
|
||||||
// -------------------------------------
|
// -------------------------------------
|
||||||
PluginAnnotationDetectingClassVisitor classVisitor = new PluginAnnotationDetectingClassVisitor();
|
PluginAnnotationDetectingClassVisitor classVisitor = new PluginAnnotationDetectingClassVisitor(classLoader);
|
||||||
|
|
||||||
String className = AsmUtils.convertTypeDescriptorToClassName(annoTypeDesc);
|
String className = AsmUtils.convertTypeDescriptorToClassName(annoTypeDesc);
|
||||||
String resourcePath = ClassUtils.convertClassNameToResourcePath(className);
|
String resourcePath = ClassUtils.convertClassNameToResourcePath(className);
|
||||||
ClassReader reader = AsmUtils.newClassReader(resourcePath);
|
ClassReader reader = AsmUtils.newClassReader(resourcePath, classLoader);
|
||||||
reader.accept(classVisitor, false);
|
reader.accept(classVisitor, false);
|
||||||
|
|
||||||
if (!classVisitor.hasPluginAnnotation())
|
if (!classVisitor.hasPluginAnnotation())
|
||||||
return super.visitAnnotation(annoTypeDesc, visible);
|
return super.visitAnnotation(annoTypeDesc, visible);
|
||||||
|
|
||||||
Class<? extends Annotation> annoType = loadToolingSafeClass(annoTypeName);
|
Class<? extends Annotation> annoType = loadToolingSafeClass(annoTypeName, classLoader);
|
||||||
|
|
||||||
if (annoType == null)
|
if (annoType == null)
|
||||||
return super.visitAnnotation(annoTypeDesc, visible);
|
return super.visitAnnotation(annoTypeDesc, visible);
|
||||||
|
|
||||||
Annotation pluginAnno = createMutableAnnotation(annoType);
|
Annotation pluginAnno = createMutableAnnotation(annoType);
|
||||||
configClass.addPluginAnnotation(pluginAnno);
|
configClass.addPluginAnnotation(pluginAnno);
|
||||||
return new MutableAnnotationVisitor(pluginAnno);
|
return new MutableAnnotationVisitor(pluginAnno, classLoader);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class PluginAnnotationDetectingClassVisitor extends ClassAdapter {
|
private static class PluginAnnotationDetectingClassVisitor extends ClassAdapter {
|
||||||
private boolean hasPluginAnnotation = false;
|
private boolean hasPluginAnnotation = false;
|
||||||
private final Extension pluginAnnotation = createMutableAnnotation(Extension.class);
|
private final Extension pluginAnnotation = createMutableAnnotation(Extension.class);
|
||||||
|
private final ClassLoader classLoader;
|
||||||
|
|
||||||
public PluginAnnotationDetectingClassVisitor() {
|
public PluginAnnotationDetectingClassVisitor(ClassLoader classLoader) {
|
||||||
super(AsmUtils.EMPTY_VISITOR);
|
super(AsmUtils.EMPTY_VISITOR);
|
||||||
|
this.classLoader = classLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AnnotationVisitor visitAnnotation(String typeDesc, boolean arg1) {
|
public AnnotationVisitor visitAnnotation(String typeDesc, boolean arg1) {
|
||||||
if (Extension.class.getName().equals(AsmUtils.convertTypeDescriptorToClassName(typeDesc))) {
|
if (Extension.class.getName().equals(AsmUtils.convertTypeDescriptorToClassName(typeDesc))) {
|
||||||
hasPluginAnnotation = true;
|
hasPluginAnnotation = true;
|
||||||
return new MutableAnnotationVisitor(pluginAnnotation);
|
return new MutableAnnotationVisitor(pluginAnnotation, classLoader);
|
||||||
}
|
}
|
||||||
return super.visitAnnotation(typeDesc, arg1);
|
return super.visitAnnotation(typeDesc, arg1);
|
||||||
}
|
}
|
||||||
|
@ -185,7 +189,7 @@ class ConfigurationClassVisitor extends ClassAdapter {
|
||||||
public MethodVisitor visitMethod(int modifiers, String methodName, String methodDescriptor, String arg3,
|
public MethodVisitor visitMethod(int modifiers, String methodName, String methodDescriptor, String arg3,
|
||||||
String[] arg4) {
|
String[] arg4) {
|
||||||
|
|
||||||
return new ConfigurationClassMethodVisitor(configClass, methodName, methodDescriptor, modifiers);
|
return new ConfigurationClassMethodVisitor(configClass, methodName, methodDescriptor, modifiers, classLoader);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -215,11 +219,11 @@ class ConfigurationClassVisitor extends ClassAdapter {
|
||||||
|
|
||||||
ConfigurationClass innerConfigClass = new ConfigurationClass();
|
ConfigurationClass innerConfigClass = new ConfigurationClass();
|
||||||
|
|
||||||
ConfigurationClassVisitor ccVisitor = new ConfigurationClassVisitor(innerConfigClass,
|
ConfigurationClassVisitor ccVisitor =
|
||||||
new ConfigurationModel());
|
new ConfigurationClassVisitor(innerConfigClass, new ConfigurationModel(), classLoader);
|
||||||
ccVisitor.setProcessInnerClasses(false);
|
ccVisitor.setProcessInnerClasses(false);
|
||||||
|
|
||||||
ClassReader reader = AsmUtils.newClassReader(name);
|
ClassReader reader = AsmUtils.newClassReader(name, classLoader);
|
||||||
reader.accept(ccVisitor, false);
|
reader.accept(ccVisitor, false);
|
||||||
|
|
||||||
if (innerClasses.containsKey(outerName))
|
if (innerClasses.containsKey(outerName))
|
||||||
|
|
|
@ -21,7 +21,7 @@ import org.springframework.config.java.Configuration;
|
||||||
import org.springframework.config.java.ConfigurationClass;
|
import org.springframework.config.java.ConfigurationClass;
|
||||||
import org.springframework.config.java.ConfigurationModel;
|
import org.springframework.config.java.ConfigurationModel;
|
||||||
import org.springframework.config.java.Util;
|
import org.springframework.config.java.Util;
|
||||||
import org.springframework.core.io.ClassPathResource;
|
import org.springframework.util.ClassUtils;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -44,6 +44,7 @@ public class ConfigurationParser {
|
||||||
* Model to be populated during calls to {@link #parse(Object, String)}
|
* Model to be populated during calls to {@link #parse(Object, String)}
|
||||||
*/
|
*/
|
||||||
private final ConfigurationModel model;
|
private final ConfigurationModel model;
|
||||||
|
private final ClassLoader classLoader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new parser instance that will be used to populate <var>model</var>.
|
* Creates a new parser instance that will be used to populate <var>model</var>.
|
||||||
|
@ -51,8 +52,9 @@ public class ConfigurationParser {
|
||||||
* @param model model to be populated by each successive call to
|
* @param model model to be populated by each successive call to
|
||||||
* {@link #parse(Object, String)}
|
* {@link #parse(Object, String)}
|
||||||
*/
|
*/
|
||||||
public ConfigurationParser(ConfigurationModel model) {
|
public ConfigurationParser(ClassLoader classLoader) {
|
||||||
this.model = model;
|
this.classLoader = classLoader;
|
||||||
|
this.model = new ConfigurationModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -63,16 +65,21 @@ public class ConfigurationParser {
|
||||||
* @param configurationId may be null, but if populated represents the bean id (assumes
|
* @param configurationId may be null, but if populated represents the bean id (assumes
|
||||||
* that this configuration class was configured via XML)
|
* that this configuration class was configured via XML)
|
||||||
*/
|
*/
|
||||||
public void parse(ClassPathResource resource, String configurationId) {
|
public void parse(String className, String configurationId) {
|
||||||
|
|
||||||
|
String resourcePath = ClassUtils.convertClassNameToResourcePath(className);
|
||||||
|
|
||||||
String resourcePath = resource.getPath();
|
ClassReader configClassReader = AsmUtils.newClassReader(Util.getClassAsStream(resourcePath, classLoader));
|
||||||
ClassReader configClassReader = AsmUtils.newClassReader(Util.getClassAsStream(resourcePath));
|
|
||||||
|
|
||||||
ConfigurationClass configClass = new ConfigurationClass();
|
ConfigurationClass configClass = new ConfigurationClass();
|
||||||
configClass.setBeanName(configurationId);
|
configClass.setBeanName(configurationId);
|
||||||
|
|
||||||
configClassReader.accept(new ConfigurationClassVisitor(configClass, model), false);
|
configClassReader.accept(new ConfigurationClassVisitor(configClass, model, classLoader), false);
|
||||||
model.add(configClass);
|
model.add(configClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ConfigurationModel getConfigurationModel() {
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,11 +36,14 @@ class MutableAnnotationArrayVisitor extends AnnotationAdapter {
|
||||||
private final MutableAnnotation mutableAnno;
|
private final MutableAnnotation mutableAnno;
|
||||||
private final String attribName;
|
private final String attribName;
|
||||||
|
|
||||||
public MutableAnnotationArrayVisitor(MutableAnnotation mutableAnno, String attribName) {
|
private final ClassLoader classLoader;
|
||||||
|
|
||||||
|
public MutableAnnotationArrayVisitor(MutableAnnotation mutableAnno, String attribName, ClassLoader classLoader) {
|
||||||
super(AsmUtils.EMPTY_VISITOR);
|
super(AsmUtils.EMPTY_VISITOR);
|
||||||
|
|
||||||
this.mutableAnno = mutableAnno;
|
this.mutableAnno = mutableAnno;
|
||||||
this.attribName = attribName;
|
this.attribName = attribName;
|
||||||
|
this.classLoader = classLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -51,14 +54,14 @@ class MutableAnnotationArrayVisitor extends AnnotationAdapter {
|
||||||
@Override
|
@Override
|
||||||
public AnnotationVisitor visitAnnotation(String na, String annoTypeDesc) {
|
public AnnotationVisitor visitAnnotation(String na, String annoTypeDesc) {
|
||||||
String annoTypeName = AsmUtils.convertTypeDescriptorToClassName(annoTypeDesc);
|
String annoTypeName = AsmUtils.convertTypeDescriptorToClassName(annoTypeDesc);
|
||||||
Class<? extends Annotation> annoType = loadToolingSafeClass(annoTypeName);
|
Class<? extends Annotation> annoType = loadToolingSafeClass(annoTypeName, classLoader);
|
||||||
|
|
||||||
if (annoType == null)
|
if (annoType == null)
|
||||||
return super.visitAnnotation(na, annoTypeDesc);
|
return super.visitAnnotation(na, annoTypeDesc);
|
||||||
|
|
||||||
Annotation anno = createMutableAnnotation(annoType);
|
Annotation anno = createMutableAnnotation(annoType);
|
||||||
values.add(anno);
|
values.add(anno);
|
||||||
return new MutableAnnotationVisitor(anno);
|
return new MutableAnnotationVisitor(anno, classLoader);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -37,6 +37,8 @@ class MutableAnnotationVisitor implements AnnotationVisitor {
|
||||||
|
|
||||||
protected final MutableAnnotation mutableAnno;
|
protected final MutableAnnotation mutableAnno;
|
||||||
|
|
||||||
|
private final ClassLoader classLoader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link MutableAnnotationVisitor} instance that will populate the the
|
* Creates a new {@link MutableAnnotationVisitor} instance that will populate the the
|
||||||
* attributes of the given <var>mutableAnno</var>. Accepts {@link Annotation} instead of
|
* attributes of the given <var>mutableAnno</var>. Accepts {@link Annotation} instead of
|
||||||
|
@ -49,13 +51,14 @@ class MutableAnnotationVisitor implements AnnotationVisitor {
|
||||||
*
|
*
|
||||||
* @see MutableAnnotationUtils#createMutableAnnotation(Class)
|
* @see MutableAnnotationUtils#createMutableAnnotation(Class)
|
||||||
*/
|
*/
|
||||||
public MutableAnnotationVisitor(Annotation mutableAnno) {
|
public MutableAnnotationVisitor(Annotation mutableAnno, ClassLoader classLoader) {
|
||||||
Assert.isInstanceOf(MutableAnnotation.class, mutableAnno, "annotation must be mutable");
|
Assert.isInstanceOf(MutableAnnotation.class, mutableAnno, "annotation must be mutable");
|
||||||
this.mutableAnno = (MutableAnnotation) mutableAnno;
|
this.mutableAnno = (MutableAnnotation) mutableAnno;
|
||||||
|
this.classLoader = classLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AnnotationVisitor visitArray(final String attribName) {
|
public AnnotationVisitor visitArray(final String attribName) {
|
||||||
return new MutableAnnotationArrayVisitor(mutableAnno, attribName);
|
return new MutableAnnotationArrayVisitor(mutableAnno, attribName, classLoader);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void visit(String attribName, Object attribValue) {
|
public void visit(String attribName, Object attribValue) {
|
||||||
|
@ -65,7 +68,7 @@ class MutableAnnotationVisitor implements AnnotationVisitor {
|
||||||
// the attribute type is Class -> load it and set it.
|
// the attribute type is Class -> load it and set it.
|
||||||
String fqClassName = ((Type) attribValue).getClassName();
|
String fqClassName = ((Type) attribValue).getClassName();
|
||||||
|
|
||||||
Class<?> classVal = loadToolingSafeClass(fqClassName);
|
Class<?> classVal = loadToolingSafeClass(fqClassName, classLoader);
|
||||||
|
|
||||||
if (classVal == null)
|
if (classVal == null)
|
||||||
return;
|
return;
|
||||||
|
@ -82,7 +85,7 @@ class MutableAnnotationVisitor implements AnnotationVisitor {
|
||||||
public void visitEnum(String attribName, String enumTypeDescriptor, String strEnumValue) {
|
public void visitEnum(String attribName, String enumTypeDescriptor, String strEnumValue) {
|
||||||
String enumClassName = AsmUtils.convertTypeDescriptorToClassName(enumTypeDescriptor);
|
String enumClassName = AsmUtils.convertTypeDescriptorToClassName(enumTypeDescriptor);
|
||||||
|
|
||||||
Class<? extends Enum> enumClass = loadToolingSafeClass(enumClassName);
|
Class<? extends Enum> enumClass = loadToolingSafeClass(enumClassName, classLoader);
|
||||||
|
|
||||||
if (enumClass == null)
|
if (enumClass == null)
|
||||||
return;
|
return;
|
||||||
|
@ -93,7 +96,7 @@ class MutableAnnotationVisitor implements AnnotationVisitor {
|
||||||
|
|
||||||
public AnnotationVisitor visitAnnotation(String attribName, String attribAnnoTypeDesc) {
|
public AnnotationVisitor visitAnnotation(String attribName, String attribAnnoTypeDesc) {
|
||||||
String annoTypeName = AsmUtils.convertTypeDescriptorToClassName(attribAnnoTypeDesc);
|
String annoTypeName = AsmUtils.convertTypeDescriptorToClassName(attribAnnoTypeDesc);
|
||||||
Class<? extends Annotation> annoType = loadToolingSafeClass(annoTypeName);
|
Class<? extends Annotation> annoType = loadToolingSafeClass(annoTypeName, classLoader);
|
||||||
|
|
||||||
if (annoType == null)
|
if (annoType == null)
|
||||||
return AsmUtils.EMPTY_VISITOR.visitAnnotation(attribName, attribAnnoTypeDesc);
|
return AsmUtils.EMPTY_VISITOR.visitAnnotation(attribName, attribAnnoTypeDesc);
|
||||||
|
@ -107,7 +110,7 @@ class MutableAnnotationVisitor implements AnnotationVisitor {
|
||||||
throw new RuntimeException(ex);
|
throw new RuntimeException(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new MutableAnnotationVisitor(anno);
|
return new MutableAnnotationVisitor(anno, classLoader);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void visitEnd() {
|
public void visitEnd() {
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
package org.springframework.config.java.support;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
|
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||||
|
import org.springframework.config.java.ConfigurationModel;
|
||||||
|
import org.springframework.config.java.internal.parsing.ConfigurationParser;
|
||||||
|
|
||||||
|
public abstract class AbstractConfigurationClassProcessor {
|
||||||
|
|
||||||
|
protected abstract BeanDefinitionRegistry getConfigurationBeanDefinitions(boolean includeAbstractBeanDefs);
|
||||||
|
|
||||||
|
protected abstract ConfigurationParser createConfigurationParser();
|
||||||
|
|
||||||
|
protected abstract void validateModel(ConfigurationModel configModel);
|
||||||
|
|
||||||
|
protected BeanDefinitionRegistry processConfigBeanDefinitions() {
|
||||||
|
BeanDefinitionRegistry configBeanDefs = getConfigurationBeanDefinitions(false);
|
||||||
|
|
||||||
|
if(configBeanDefs.getBeanDefinitionCount() == 0)
|
||||||
|
return configBeanDefs; // nothing to do - don't waste any more cycles
|
||||||
|
|
||||||
|
ConfigurationModel configModel = createConfigurationModelFor(configBeanDefs);
|
||||||
|
|
||||||
|
validateModel(configModel);
|
||||||
|
|
||||||
|
return renderModelAsBeanDefinitions(configModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConfigurationModel createConfigurationModelFor(BeanDefinitionRegistry configBeanDefinitions) {
|
||||||
|
|
||||||
|
ConfigurationParser parser = createConfigurationParser();
|
||||||
|
|
||||||
|
for(String beanName : configBeanDefinitions.getBeanDefinitionNames()) {
|
||||||
|
BeanDefinition beanDef = configBeanDefinitions.getBeanDefinition(beanName);
|
||||||
|
String className = beanDef.getBeanClassName();
|
||||||
|
|
||||||
|
parser.parse(className, beanName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parser.getConfigurationModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
private BeanDefinitionRegistry renderModelAsBeanDefinitions(ConfigurationModel configModel) {
|
||||||
|
return new ConfigurationModelBeanDefinitionReader().loadBeanDefinitions(configModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -16,11 +16,6 @@
|
||||||
package org.springframework.config.java.support;
|
package org.springframework.config.java.support;
|
||||||
|
|
||||||
import static java.lang.String.*;
|
import static java.lang.String.*;
|
||||||
import static org.springframework.config.java.Util.*;
|
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Comparator;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
@ -28,19 +23,16 @@ import org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostPr
|
||||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionReader;
|
import org.springframework.beans.factory.support.BeanDefinitionReader;
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
|
||||||
import org.springframework.beans.factory.support.GenericBeanDefinition;
|
import org.springframework.beans.factory.support.GenericBeanDefinition;
|
||||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||||
|
import org.springframework.beans.factory.support.SimpleBeanDefinitionRegistry;
|
||||||
|
import org.springframework.config.java.BeanMethod;
|
||||||
import org.springframework.config.java.Configuration;
|
import org.springframework.config.java.Configuration;
|
||||||
import org.springframework.config.java.ConfigurationClass;
|
import org.springframework.config.java.ConfigurationClass;
|
||||||
import org.springframework.config.java.ConfigurationModel;
|
import org.springframework.config.java.ConfigurationModel;
|
||||||
import org.springframework.config.java.FactoryMethod;
|
import org.springframework.config.java.FactoryMethod;
|
||||||
import org.springframework.config.java.ModelMethod;
|
|
||||||
import org.springframework.config.java.plugin.Extension;
|
import org.springframework.config.java.plugin.Extension;
|
||||||
import org.springframework.config.java.plugin.ExtensionAnnotationBeanDefinitionRegistrar;
|
|
||||||
import org.springframework.core.annotation.AnnotationUtils;
|
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -57,29 +49,28 @@ class ConfigurationModelBeanDefinitionReader {
|
||||||
|
|
||||||
private static final Log log = LogFactory.getLog(ConfigurationModelBeanDefinitionReader.class);
|
private static final Log log = LogFactory.getLog(ConfigurationModelBeanDefinitionReader.class);
|
||||||
|
|
||||||
private final DefaultListableBeanFactory beanFactory;
|
private BeanDefinitionRegistry registry;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link ConfigurationModelBeanDefinitionReader} instance.
|
* Creates a new {@link ConfigurationModelBeanDefinitionReader} instance.
|
||||||
*/
|
*/
|
||||||
public ConfigurationModelBeanDefinitionReader(DefaultListableBeanFactory beanFactory) {
|
public ConfigurationModelBeanDefinitionReader() {
|
||||||
this.beanFactory = beanFactory;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads {@code model}, registering bean definitions with {@link #beanFactory} based on
|
* Reads {@code model}, registering bean definitions with {@link #registry} based on
|
||||||
* its contents.
|
* its contents.
|
||||||
*
|
*
|
||||||
* @return number of bean definitions generated
|
* @return number of bean definitions generated
|
||||||
*/
|
*/
|
||||||
public int loadBeanDefinitions(ConfigurationModel model) {
|
public BeanDefinitionRegistry loadBeanDefinitions(ConfigurationModel model) {
|
||||||
int initialBeanDefCount = beanFactory.getBeanDefinitionCount();
|
registry = new SimpleBeanDefinitionRegistry();
|
||||||
|
|
||||||
for (ConfigurationClass configClass : model.getAllConfigurationClasses())
|
for (ConfigurationClass configClass : model.getAllConfigurationClasses())
|
||||||
loadBeanDefinitionsForConfigurationClass(configClass);
|
loadBeanDefinitionsForConfigurationClass(configClass);
|
||||||
|
|
||||||
return beanFactory.getBeanDefinitionCount() - initialBeanDefCount;
|
return registry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -90,21 +81,23 @@ class ConfigurationModelBeanDefinitionReader {
|
||||||
private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass) {
|
private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass) {
|
||||||
doLoadBeanDefinitionForConfigurationClass(configClass);
|
doLoadBeanDefinitionForConfigurationClass(configClass);
|
||||||
|
|
||||||
for (ModelMethod method : configClass.getMethods())
|
for (BeanMethod method : configClass.getMethods())
|
||||||
loadBeanDefinitionsForModelMethod(method);
|
loadBeanDefinitionsForModelMethod(method);
|
||||||
|
|
||||||
Annotation[] pluginAnnotations = configClass.getPluginAnnotations();
|
// Annotation[] pluginAnnotations = configClass.getPluginAnnotations();
|
||||||
Arrays.sort(pluginAnnotations, new PluginComparator());
|
// Arrays.sort(pluginAnnotations, new PluginComparator());
|
||||||
for (Annotation annotation : pluginAnnotations)
|
// for (Annotation annotation : pluginAnnotations)
|
||||||
loadBeanDefinitionsForExtensionAnnotation(annotation);
|
// loadBeanDefinitionsForExtensionAnnotation(beanDefs, annotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers the {@link Configuration} class itself as a bean definition.
|
* Registers the {@link Configuration} class itself as a bean definition.
|
||||||
|
* @param beanDefs
|
||||||
*/
|
*/
|
||||||
private void doLoadBeanDefinitionForConfigurationClass(ConfigurationClass configClass) {
|
private void doLoadBeanDefinitionForConfigurationClass(ConfigurationClass configClass) {
|
||||||
Configuration metadata = configClass.getMetadata();
|
Configuration metadata = configClass.getMetadata();
|
||||||
|
|
||||||
|
// TODO: think about implications with annotation-config
|
||||||
if (metadata.checkRequired() == true) {
|
if (metadata.checkRequired() == true) {
|
||||||
RootBeanDefinition requiredAnnotationPostProcessor = new RootBeanDefinition();
|
RootBeanDefinition requiredAnnotationPostProcessor = new RootBeanDefinition();
|
||||||
Class<?> beanClass = RequiredAnnotationBeanPostProcessor.class;
|
Class<?> beanClass = RequiredAnnotationBeanPostProcessor.class;
|
||||||
|
@ -112,7 +105,7 @@ class ConfigurationModelBeanDefinitionReader {
|
||||||
requiredAnnotationPostProcessor.setBeanClass(beanClass);
|
requiredAnnotationPostProcessor.setBeanClass(beanClass);
|
||||||
requiredAnnotationPostProcessor
|
requiredAnnotationPostProcessor
|
||||||
.setResourceDescription("ensures @Required methods have been invoked");
|
.setResourceDescription("ensures @Required methods have been invoked");
|
||||||
beanFactory.registerBeanDefinition(beanName, requiredAnnotationPostProcessor);
|
registry.registerBeanDefinition(beanName, requiredAnnotationPostProcessor);
|
||||||
}
|
}
|
||||||
|
|
||||||
GenericBeanDefinition configBeanDef = new GenericBeanDefinition();
|
GenericBeanDefinition configBeanDef = new GenericBeanDefinition();
|
||||||
|
@ -122,13 +115,13 @@ class ConfigurationModelBeanDefinitionReader {
|
||||||
|
|
||||||
// consider the case where it's already been defined (probably in XML)
|
// consider the case where it's already been defined (probably in XML)
|
||||||
// and potentially has PropertyValues and ConstructorArgs)
|
// and potentially has PropertyValues and ConstructorArgs)
|
||||||
if (beanFactory.containsBeanDefinition(configBeanName)) {
|
if (registry.containsBeanDefinition(configBeanName)) {
|
||||||
if (log.isInfoEnabled())
|
if (log.isInfoEnabled())
|
||||||
log.info(format(
|
log.info(format(
|
||||||
"Copying property and constructor arg values from existing bean definition for "
|
"Copying property and constructor arg values from existing bean definition for "
|
||||||
+ "@Configuration class %s to new bean definition", configBeanName));
|
+ "@Configuration class %s to new bean definition", configBeanName));
|
||||||
AbstractBeanDefinition existing = (AbstractBeanDefinition) beanFactory
|
AbstractBeanDefinition existing =
|
||||||
.getBeanDefinition(configBeanName);
|
(AbstractBeanDefinition) registry.getBeanDefinition(configBeanName);
|
||||||
configBeanDef.setPropertyValues(existing.getPropertyValues());
|
configBeanDef.setPropertyValues(existing.getPropertyValues());
|
||||||
configBeanDef.setConstructorArgumentValues(existing.getConstructorArgumentValues());
|
configBeanDef.setConstructorArgumentValues(existing.getConstructorArgumentValues());
|
||||||
configBeanDef.setResource(existing.getResource());
|
configBeanDef.setResource(existing.getResource());
|
||||||
|
@ -137,52 +130,52 @@ class ConfigurationModelBeanDefinitionReader {
|
||||||
if (log.isInfoEnabled())
|
if (log.isInfoEnabled())
|
||||||
log.info(format("Registering bean definition for @Configuration class %s", configBeanName));
|
log.info(format("Registering bean definition for @Configuration class %s", configBeanName));
|
||||||
|
|
||||||
beanFactory.registerBeanDefinition(configBeanName, configBeanDef);
|
registry.registerBeanDefinition(configBeanName, configBeanDef);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads a particular {@link ModelMethod}, registering bean definitions with
|
* Reads a particular {@link BeanMethod}, registering bean definitions with
|
||||||
* {@link #beanFactory} based on its contents.
|
* {@link #registry} based on its contents.
|
||||||
*
|
*
|
||||||
* @see FactoryMethod
|
* @see FactoryMethod
|
||||||
*/
|
*/
|
||||||
private void loadBeanDefinitionsForModelMethod(ModelMethod method) {
|
private void loadBeanDefinitionsForModelMethod(BeanMethod method) {
|
||||||
method.getRegistrar().register(method, beanFactory);
|
method.getRegistrar().register(method, registry);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
// @SuppressWarnings("unchecked")
|
||||||
private void loadBeanDefinitionsForExtensionAnnotation(Annotation anno) {
|
// private void loadBeanDefinitionsForExtensionAnnotation(Map<String, BeanDefinition> beanDefs, Annotation anno) {
|
||||||
// ExtensionAnnotationUtils.getRegistrarFor(anno).registerBeanDefinitionsWith(beanFactory);
|
// // ExtensionAnnotationUtils.getRegistrarFor(anno).registerBeanDefinitionsWith(beanFactory);
|
||||||
// there is a fixed assumption that in order for this annotation to have
|
// // there is a fixed assumption that in order for this annotation to have
|
||||||
// been registered in the first place, it must be meta-annotated with @Plugin
|
// // been registered in the first place, it must be meta-annotated with @Plugin
|
||||||
// assert this as an invariant now
|
// // assert this as an invariant now
|
||||||
Class<?> annoClass = anno.getClass();
|
// Class<?> annoClass = anno.getClass();
|
||||||
Extension extensionAnno = AnnotationUtils.findAnnotation(annoClass, Extension.class);
|
// Extension extensionAnno = AnnotationUtils.findAnnotation(annoClass, Extension.class);
|
||||||
Assert.isTrue(extensionAnno != null, format("%s annotation is not annotated as a @%s", annoClass,
|
// Assert.isTrue(extensionAnno != null, format("%s annotation is not annotated as a @%s", annoClass,
|
||||||
Extension.class.getSimpleName()));
|
// Extension.class.getSimpleName()));
|
||||||
|
//
|
||||||
Class<? extends ExtensionAnnotationBeanDefinitionRegistrar> extHandlerClass = extensionAnno.handler();
|
// Class<? extends ExtensionAnnotationBeanDefinitionRegistrar> extHandlerClass = extensionAnno.handler();
|
||||||
|
//
|
||||||
ExtensionAnnotationBeanDefinitionRegistrar extHandler = getInstance(extHandlerClass);
|
// ExtensionAnnotationBeanDefinitionRegistrar extHandler = getInstance(extHandlerClass);
|
||||||
extHandler.handle(anno, beanFactory);
|
// extHandler.handle(anno, beanFactory);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private static class PluginComparator implements Comparator<Annotation> {
|
// private static class PluginComparator implements Comparator<Annotation> {
|
||||||
public int compare(Annotation a1, Annotation a2) {
|
// public int compare(Annotation a1, Annotation a2) {
|
||||||
Integer i1 = getOrder(a1);
|
// Integer i1 = getOrder(a1);
|
||||||
Integer i2 = getOrder(a2);
|
// Integer i2 = getOrder(a2);
|
||||||
return i1.compareTo(i2);
|
// return i1.compareTo(i2);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private Integer getOrder(Annotation a) {
|
// private Integer getOrder(Annotation a) {
|
||||||
Extension plugin = a.annotationType().getAnnotation(Extension.class);
|
// Extension plugin = a.annotationType().getAnnotation(Extension.class);
|
||||||
if (plugin == null)
|
// if (plugin == null)
|
||||||
throw new IllegalArgumentException("annotation was not annotated with @Plugin: "
|
// throw new IllegalArgumentException("annotation was not annotated with @Plugin: "
|
||||||
+ a.annotationType());
|
// + a.annotationType());
|
||||||
return plugin.order();
|
// return plugin.order();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,10 +15,10 @@
|
||||||
*/
|
*/
|
||||||
package org.springframework.config.java.support;
|
package org.springframework.config.java.support;
|
||||||
|
|
||||||
import static org.springframework.config.java.Util.*;
|
import static java.lang.String.*;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
@ -27,6 +27,7 @@ import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||||
|
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||||
import org.springframework.config.java.Configuration;
|
import org.springframework.config.java.Configuration;
|
||||||
import org.springframework.config.java.ConfigurationModel;
|
import org.springframework.config.java.ConfigurationModel;
|
||||||
|
@ -35,17 +36,21 @@ import org.springframework.config.java.UsageError;
|
||||||
import org.springframework.config.java.internal.enhancement.ConfigurationEnhancer;
|
import org.springframework.config.java.internal.enhancement.ConfigurationEnhancer;
|
||||||
import org.springframework.config.java.internal.parsing.ConfigurationParser;
|
import org.springframework.config.java.internal.parsing.ConfigurationParser;
|
||||||
import org.springframework.core.Ordered;
|
import org.springframework.core.Ordered;
|
||||||
import org.springframework.core.io.ClassPathResource;
|
import org.springframework.core.type.AnnotationMetadata;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.core.type.classreading.MetadataReader;
|
||||||
|
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link BeanFactoryPostProcessor} used for bootstrapping {@link Configuration
|
* {@link BeanFactoryPostProcessor} used for bootstrapping {@link Configuration
|
||||||
* @Configuration} beans from Spring XML files.
|
* @Configuration} beans. Usually used in conjunction with Spring XML files.
|
||||||
*/
|
*/
|
||||||
public class ConfigurationPostProcessor implements Ordered, BeanFactoryPostProcessor {
|
public class ConfigurationPostProcessor extends AbstractConfigurationClassProcessor
|
||||||
|
implements Ordered, BeanFactoryPostProcessor {
|
||||||
|
|
||||||
private static final Log logger = LogFactory.getLog(ConfigurationPostProcessor.class);
|
private static final Log logger = LogFactory.getLog(ConfigurationPostProcessor.class);
|
||||||
|
private DefaultListableBeanFactory beanFactory;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -55,58 +60,102 @@ public class ConfigurationPostProcessor implements Ordered, BeanFactoryPostProce
|
||||||
public int getOrder() {
|
public int getOrder() {
|
||||||
return Ordered.HIGHEST_PRECEDENCE;
|
return Ordered.HIGHEST_PRECEDENCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void postProcessBeanFactory(ConfigurableListableBeanFactory clBeanFactory) throws BeansException {
|
||||||
|
Assert.isInstanceOf(DefaultListableBeanFactory.class, clBeanFactory);
|
||||||
|
beanFactory = (DefaultListableBeanFactory) clBeanFactory;
|
||||||
|
|
||||||
|
BeanDefinitionRegistry factoryBeanDefs = processConfigBeanDefinitions();
|
||||||
|
|
||||||
|
for(String beanName : factoryBeanDefs.getBeanDefinitionNames())
|
||||||
|
beanFactory.registerBeanDefinition(beanName, factoryBeanDefs.getBeanDefinition(beanName));
|
||||||
|
|
||||||
|
enhanceConfigurationClasses();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ConfigurationParser createConfigurationParser() {
|
||||||
|
return new ConfigurationParser(beanFactory.getBeanClassLoader());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Searches <var>beanFactory</var> for any {@link Configuration} classes in order to
|
* @return map of all non-abstract {@link BeanDefinition}s in the enclosing {@link #beanFactory}
|
||||||
* parse and enhance them. Also registers any {@link BeanPostProcessor} objects
|
|
||||||
* necessary to fulfill JavaConfig requirements.
|
|
||||||
*/
|
*/
|
||||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory clBeanFactory) throws BeansException {
|
@Override
|
||||||
if (!(clBeanFactory instanceof DefaultListableBeanFactory))
|
protected BeanDefinitionRegistry getConfigurationBeanDefinitions(boolean includeAbstractBeanDefs) {
|
||||||
throw new IllegalStateException("beanFactory must be of type "
|
|
||||||
+ DefaultListableBeanFactory.class.getSimpleName());
|
BeanDefinitionRegistry configBeanDefs = new DefaultListableBeanFactory();
|
||||||
|
|
||||||
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) clBeanFactory;
|
|
||||||
|
|
||||||
ConfigurationModel model = new ConfigurationModel();
|
|
||||||
|
|
||||||
parseAnyConfigurationClasses(beanFactory, model);
|
|
||||||
|
|
||||||
enhanceAnyConfigurationClasses(beanFactory, model);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void parseAnyConfigurationClasses(DefaultListableBeanFactory beanFactory, ConfigurationModel model) {
|
|
||||||
|
|
||||||
// linked map is important for maintaining predictable ordering of configuration
|
|
||||||
// classes.
|
|
||||||
// this is important in bean / value override situations.
|
|
||||||
LinkedHashMap<String, ClassPathResource> configClassResources = new LinkedHashMap<String, ClassPathResource>();
|
|
||||||
|
|
||||||
for (String beanName : beanFactory.getBeanDefinitionNames()) {
|
for (String beanName : beanFactory.getBeanDefinitionNames()) {
|
||||||
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
|
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
|
||||||
if (beanDef.isAbstract())
|
|
||||||
|
if (beanDef.isAbstract() && !includeAbstractBeanDefs)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (isConfigClass(beanDef)) {
|
if (isConfigClass(beanDef))
|
||||||
String path = ClassUtils.convertClassNameToResourcePath(beanDef.getBeanClassName());
|
configBeanDefs.registerBeanDefinition(beanName, beanDef);
|
||||||
configClassResources.put(beanName, new ClassPathResource(path));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigurationModelBeanDefinitionReader modelBeanDefinitionReader = new ConfigurationModelBeanDefinitionReader(
|
return configBeanDefs;
|
||||||
beanFactory);
|
}
|
||||||
ConfigurationParser parser = new ConfigurationParser(model);
|
|
||||||
|
// /**
|
||||||
for (String id : configClassResources.keySet())
|
// * Searches <var>beanFactory</var> for any {@link Configuration} classes in order to
|
||||||
parser.parse(configClassResources.get(id), id);
|
// * parse and enhance them. Also registers any {@link BeanPostProcessor} objects
|
||||||
|
// * necessary to fulfill JavaConfig requirements.
|
||||||
|
// */
|
||||||
|
// public void postProcessBeanFactory2(ConfigurableListableBeanFactory clBeanFactory) throws BeansException {
|
||||||
|
// Assert.isInstanceOf(DefaultListableBeanFactory.class, clBeanFactory);
|
||||||
|
// DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) clBeanFactory;
|
||||||
|
//
|
||||||
|
// ConfigurationModel model = parseAnyConfigurationClasses(beanFactory);
|
||||||
|
//
|
||||||
|
// enhanceAnyConfigurationClasses(beanFactory, model);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private ConfigurationModel parseAnyConfigurationClasses(DefaultListableBeanFactory beanFactory) {
|
||||||
|
//
|
||||||
|
// // linked map is important for maintaining predictable ordering of configuration
|
||||||
|
// // classes.
|
||||||
|
// // this is important in bean / value override situations.
|
||||||
|
// LinkedHashMap<String, ClassPathResource> configClassResources = new LinkedHashMap<String, ClassPathResource>();
|
||||||
|
//
|
||||||
|
// for (String beanName : beanFactory.getBeanDefinitionNames()) {
|
||||||
|
// BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
|
||||||
|
// if (beanDef.isAbstract())
|
||||||
|
// continue;
|
||||||
|
//
|
||||||
|
// if (isConfigClass(beanDef)) {
|
||||||
|
// String path = ClassUtils.convertClassNameToResourcePath(beanDef.getBeanClassName());
|
||||||
|
// configClassResources.put(beanName, new ClassPathResource(path));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// ConfigurationModelBeanDefinitionReader modelBeanDefinitionReader = new ConfigurationModelBeanDefinitionReader(
|
||||||
|
// beanFactory);
|
||||||
|
// ConfigurationParser parser = new ConfigurationParser(ClassUtils.getDefaultClassLoader());
|
||||||
|
//
|
||||||
|
// for (String id : configClassResources.keySet())
|
||||||
|
// parser.parse(configClassResources.get(id).getPath(), id);
|
||||||
|
//
|
||||||
|
// ConfigurationModel model = parser.getConfigurationModel();
|
||||||
|
//
|
||||||
|
// ArrayList<UsageError> errors = new ArrayList<UsageError>();
|
||||||
|
// model.validate(errors);
|
||||||
|
// if (errors.size() > 0)
|
||||||
|
// throw new MalformedConfigurationException(errors.toArray(new UsageError[] {}));
|
||||||
|
//
|
||||||
|
// modelBeanDefinitionReader.loadBeanDefinitions(model);
|
||||||
|
//
|
||||||
|
// return model;
|
||||||
|
// }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void validateModel(ConfigurationModel model) {
|
||||||
ArrayList<UsageError> errors = new ArrayList<UsageError>();
|
ArrayList<UsageError> errors = new ArrayList<UsageError>();
|
||||||
model.validate(errors);
|
model.validate(errors);
|
||||||
if (errors.size() > 0)
|
if (errors.size() > 0)
|
||||||
throw new MalformedConfigurationException(errors.toArray(new UsageError[] {}));
|
throw new MalformedConfigurationException(errors.toArray(new UsageError[] {}));
|
||||||
|
|
||||||
modelBeanDefinitionReader.loadBeanDefinitions(model);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -118,55 +167,43 @@ public class ConfigurationPostProcessor implements Ordered, BeanFactoryPostProce
|
||||||
* @see ConfigurationEnhancer
|
* @see ConfigurationEnhancer
|
||||||
* @see BeanFactoryPostProcessor
|
* @see BeanFactoryPostProcessor
|
||||||
*/
|
*/
|
||||||
private void enhanceAnyConfigurationClasses(DefaultListableBeanFactory beanFactory,
|
private void enhanceConfigurationClasses() {
|
||||||
ConfigurationModel model) {
|
|
||||||
|
|
||||||
ConfigurationEnhancer enhancer = new ConfigurationEnhancer(beanFactory, model);
|
ConfigurationEnhancer enhancer = new ConfigurationEnhancer(beanFactory);
|
||||||
|
|
||||||
int configClassesEnhanced = 0;
|
BeanDefinitionRegistry configBeanDefs = getConfigurationBeanDefinitions(true);
|
||||||
|
|
||||||
for (String beanName : beanFactory.getBeanDefinitionNames()) {
|
for(String beanName : configBeanDefs.getBeanDefinitionNames()) {
|
||||||
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
|
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
|
||||||
|
|
||||||
if (!isConfigClass(beanDef))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
String configClassName = beanDef.getBeanClassName();
|
String configClassName = beanDef.getBeanClassName();
|
||||||
|
|
||||||
String enhancedClassName = enhancer.enhance(configClassName);
|
String enhancedClassName = enhancer.enhance(configClassName);
|
||||||
|
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isDebugEnabled())
|
||||||
logger
|
logger.debug(format("Replacing bean definition '%s' existing class name '%s' with enhanced class name '%s'",
|
||||||
.debug(String
|
beanName, configClassName, enhancedClassName));
|
||||||
.format(
|
|
||||||
"Replacing bean definition '%s' existing class name '%s' with enhanced class name '%s'",
|
|
||||||
beanName, configClassName, enhancedClassName));
|
|
||||||
|
|
||||||
beanDef.setBeanClassName(enhancedClassName);
|
beanDef.setBeanClassName(enhancedClassName);
|
||||||
|
|
||||||
configClassesEnhanced++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (configClassesEnhanced == 0)
|
|
||||||
logger.warn("Found no @Configuration class BeanDefinitions within " + beanFactory);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines whether the class for <var>beanDef</var> is a {@link Configuration}
|
* Determines whether the class for <var>beanDef</var> is a {@link Configuration}
|
||||||
* -annotated class. Returns false if <var>beanDef</var> has no class specified.
|
* -annotated class. Returns false if <var>beanDef</var> has no class specified.
|
||||||
* <p>
|
|
||||||
* Note: the classloading used within should not be problematic or interfere with
|
|
||||||
* tooling in any way. BeanFactoryPostProcessing happens only during actual runtime
|
|
||||||
* processing via {@link JavaConfigApplicationContext} or via XML using
|
|
||||||
* {@link ConfigurationPostProcessor}. In any case, tooling (Spring IDE) will hook in at
|
|
||||||
* a lower level than this class and thus never encounter this classloading. Should this
|
|
||||||
* become problematic, it would not be too difficult to replace the following with ASM
|
|
||||||
* logic that traverses the class hierarchy in order to find whether the class is
|
|
||||||
* directly or indirectly annotated with {@link Configuration}.
|
|
||||||
*/
|
*/
|
||||||
private static boolean isConfigClass(BeanDefinition beanDef) {
|
private static boolean isConfigClass(BeanDefinition beanDef) {
|
||||||
|
|
||||||
String className = beanDef.getBeanClassName();
|
String className = beanDef.getBeanClassName();
|
||||||
return className != null && loadRequiredClass(className).isAnnotationPresent(Configuration.class);
|
|
||||||
|
if(className == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
MetadataReader metadataReader = new SimpleMetadataReaderFactory().getMetadataReader(className);
|
||||||
|
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
|
||||||
|
return annotationMetadata.hasAnnotation(Configuration.class.getName());
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,4 +11,5 @@
|
||||||
|
|
||||||
<bean class="test.basic.AutowiredConfigurationTests$AutowiredConfig"/>
|
<bean class="test.basic.AutowiredConfigurationTests$AutowiredConfig"/>
|
||||||
<bean class="test.basic.AutowiredConfigurationTests$ColorConfig"/>
|
<bean class="test.basic.AutowiredConfigurationTests$ColorConfig"/>
|
||||||
|
|
||||||
</beans>
|
</beans>
|
||||||
|
|
|
@ -10,6 +10,7 @@ import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostP
|
||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||||
import org.springframework.config.java.Configuration;
|
import org.springframework.config.java.Configuration;
|
||||||
|
import org.springframework.config.java.MalformedConfigurationException;
|
||||||
import org.springframework.config.java.Scopes;
|
import org.springframework.config.java.Scopes;
|
||||||
import org.springframework.config.java.ext.Bean;
|
import org.springframework.config.java.ext.Bean;
|
||||||
import org.springframework.config.java.support.ConfigurationPostProcessor;
|
import org.springframework.config.java.support.ConfigurationPostProcessor;
|
||||||
|
@ -100,4 +101,63 @@ public class BasicTests {
|
||||||
return new TestBean("bar");
|
return new TestBean("bar");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void legalBeanOverriding() {
|
||||||
|
{
|
||||||
|
BeanFactory factory = initBeanFactory(ConfigWithBeanThatAllowsOverriding.class, ConfigWithBeanOverride.class);
|
||||||
|
|
||||||
|
TestBean testBean = factory.getBean("testBean", TestBean.class);
|
||||||
|
|
||||||
|
assertThat(testBean.getName(), equalTo("overridden"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// now try it the other way around - order matters!
|
||||||
|
|
||||||
|
{
|
||||||
|
BeanFactory factory = initBeanFactory(ConfigWithBeanOverride.class, ConfigWithBeanThatAllowsOverriding.class);
|
||||||
|
|
||||||
|
TestBean testBean = factory.getBean("testBean", TestBean.class);
|
||||||
|
|
||||||
|
assertThat(testBean.getName(), equalTo("original"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected=MalformedConfigurationException.class)
|
||||||
|
public void illegalBeanOverriding() {
|
||||||
|
initBeanFactory(ConfigWithBeanThatDisallowsOverriding.class, ConfigWithBeanOverride.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void illegalBeanOverriding2() {
|
||||||
|
// should be okay when the class that disallows overriding is the one doing the overriding
|
||||||
|
initBeanFactory(ConfigWithBeanOverride.class, ConfigWithBeanThatDisallowsOverriding.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class ConfigWithBeanThatAllowsOverriding {
|
||||||
|
@Bean
|
||||||
|
public TestBean testBean() {
|
||||||
|
return new TestBean("original");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class ConfigWithBeanThatDisallowsOverriding {
|
||||||
|
@Bean(allowOverriding = false)
|
||||||
|
public TestBean testBean() {
|
||||||
|
return new TestBean("original");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class ConfigWithBeanOverride {
|
||||||
|
@Bean
|
||||||
|
public TestBean testBean() {
|
||||||
|
return new TestBean("overridden");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,4 +10,8 @@
|
||||||
<bean class="org.springframework.config.java.support.ConfigurationPostProcessor"/>
|
<bean class="org.springframework.config.java.support.ConfigurationPostProcessor"/>
|
||||||
|
|
||||||
<bean class="test.basic.AutowiredConfigurationTests$ValueConfig"/>
|
<bean class="test.basic.AutowiredConfigurationTests$ValueConfig"/>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<context:component-scan base-package="test.basic.value"/>
|
||||||
|
-->
|
||||||
</beans>
|
</beans>
|
||||||
|
|
Loading…
Reference in New Issue