diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/Configuration.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/Configuration.java
index 832ba30e9d2..84d01b7adf4 100644
--- a/org.springframework.config.java/src/main/java/org/springframework/config/java/Configuration.java
+++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/Configuration.java
@@ -29,70 +29,74 @@ import org.springframework.stereotype.Component;
/**
- * Annotation indicating that a class is a "Java Configuration" class, meaning that it exposes one
- * or more {@link Bean} methods. Holds similar information to that held in the default values of a
- * bean factory; can generally be thought of as the JavaConfig equivalent of XML's 'beans' root
- * element.
- *
- *
Note however that the information here is not used to populate the defaults of the owning bean
- * factory, which would affect other configurations. In the style of the Java configuration
- * mechanism generally, each Java configuration class is kept isolated.
- *
- *
Configuration-annotated classes are also candidates for component scanning thanks to the fact
- * that this annotation is meta-annotated with {@link Component @Component}.
- *
- * @author Rod Johnson
- * @author Chris Beams
+ * Annotation indicating that a class is a "Java Configuration" class, meaning that it
+ * exposes one or more {@link Bean} methods. Holds similar information to that held in the
+ * default values of a bean factory; can generally be thought of as the JavaConfig
+ * equivalent of XML's 'beans' root element.
+ *
+ *
+ * Note however that the information here is not used to populate the defaults of the owning
+ * bean factory, which would affect other configurations. In the style of the Java
+ * configuration mechanism generally, each Java configuration class is kept isolated.
+ *
+ *
+ *
+ * Configuration-annotated classes are also candidates for component scanning thanks to the
+ * fact that this annotation is meta-annotated with {@link Component @Component}.
+ *
+ *
+ * @author Rod Johnson
+ * @author Chris Beams
*/
@Component
-@Target({ ElementType.TYPE })
+@Target( { ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Configuration {
- /**
- * Configuration name. Allow different variants, such as test, production
- * etc. Default will always match.
- * @return
- */
- String[] names() default "";
+ /**
+ * Configuration name. Allow different variants, such as test, production etc. Default
+ * will always match.
+ *
+ * @return
+ */
+ String[] names() default "";
- /**
- * Specifies the default autowiring strategy.
- *
- * @see Autowire
- * @return
- */
- Autowire defaultAutowire() default Autowire.INHERITED;
+ /**
+ * Specifies the default autowiring strategy.
+ *
+ * @see Autowire
+ * @return
+ */
+ Autowire defaultAutowire() default Autowire.INHERITED;
-// /**
-// * Dependency check strategy. By default, the dependency check is
-// * unspecified, that is the default Spring option will apply. In most cases,
-// * it means no dependency check will be done.
-// *
-// * @see DependencyCheck
-// * @return
-// */
-// DependencyCheck defaultDependencyCheck() default DependencyCheck.UNSPECIFIED;
-//
-// /**
-// * Bean instantiation strategy. By default, it is unspecified.
-// *
-// * @see Lazy
-// * @return
-// */
-// Lazy defaultLazy() default Lazy.UNSPECIFIED;
+ // /**
+ // * Dependency check strategy. By default, the dependency check is
+ // * unspecified, that is the default Spring option will apply. In most cases,
+ // * it means no dependency check will be done.
+ // *
+ // * @see DependencyCheck
+ // * @return
+ // */
+ // DependencyCheck defaultDependencyCheck() default DependencyCheck.UNSPECIFIED;
+ //
+ // /**
+ // * Bean instantiation strategy. By default, it is unspecified.
+ // *
+ // * @see Lazy
+ // * @return
+ // */
+ // Lazy defaultLazy() default Lazy.UNSPECIFIED;
- /**
- * Do we autowire with aspects from the enclosing factory scope?
- */
- boolean useFactoryAspects() default false;
+ /**
+ * Do we autowire with aspects from the enclosing factory scope?
+ */
+ boolean useFactoryAspects() default false;
- /**
- * Do we check {@link Required @Required} methods to make sure they've been
- * called?
- */
- boolean checkRequired() default false;
+ /**
+ * Do we check {@link Required @Required} methods to make sure they've been called?
+ */
+ boolean checkRequired() default false;
}
diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/ConfigurationClass.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/ConfigurationClass.java
index 732e481969f..cb6fabddf9a 100644
--- a/org.springframework.config.java/src/main/java/org/springframework/config/java/ConfigurationClass.java
+++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/ConfigurationClass.java
@@ -30,308 +30,312 @@ import sun.security.x509.Extension;
/**
- * Abstract representation of a user-defined {@link Configuration @Configuration} class. Includes a
- * set of Bean methods, AutoBean methods, ExternalBean methods, ExternalValue methods, etc. Includes
- * all such methods defined in the ancestry of the class, in a 'flattened-out' manner. Note that
- * each BeanMethod representation does still contain source information about where it was
- * originally detected (for the purpose of tooling with Spring IDE).
- *
- *
Like the rest of the {@link org.springframework.config.java.model model} package,
- * this class follows the fluent interface / builder pattern such that a model can be built up
- * easily by method chaining.
- *
- * @author Chris Beams
+ * Abstract representation of a user-defined {@link Configuration @Configuration} class.
+ * Includes a set of Bean methods, AutoBean methods, ExternalBean methods, ExternalValue
+ * methods, etc. Includes all such methods defined in the ancestry of the class, in a
+ * 'flattened-out' manner. Note that each BeanMethod representation does still contain
+ * source information about where it was originally detected (for the purpose of tooling
+ * with Spring IDE).
+ *
+ *
+ * Like the rest of the {@link org.springframework.config.java.model model} package, this
+ * class follows the fluent interface / builder pattern such that a model can be built up
+ * easily by method chaining.
+ *
+ *
+ * @author Chris Beams
*/
// TODO: SJC-242 update documentation in light of generalization changes
// consider removing all refs to Bean, ExternalBean, etc.
public final class ConfigurationClass extends ModelClass implements Validatable {
- private String beanName;
-
- private int modifiers;
-
- private Configuration metadata;
-
- private HashSet methods = new HashSet();
-
- private HashSet pluginAnnotations = new HashSet();
-
- private ConfigurationClass declaringClass;
-
- public ConfigurationClass() { }
-
- // TODO: get rid of constructors used only for testing. put in testing util.
- /**
- * Creates a new ConfigurationClass named className.
- *
- * @param name fully-qualified Configuration class being represented
- *
- * @see #setClassName(String)
- */
- ConfigurationClass(String name) {
- this(name, null, defaultAnnotation(), 0);
- }
-
- ConfigurationClass(String name, Configuration metadata) {
- this(name, null, metadata, 0);
- }
-
- ConfigurationClass(String name, int modifiers) {
- this(name, null, defaultAnnotation(), modifiers);
- }
-
- private static Configuration defaultAnnotation() {
- @Configuration class Prototype { }
- return Prototype.class.getAnnotation(Configuration.class);
- }
-
- /**
- * Creates a new ConfigurationClass object.
- *
- * @param name Fully qualified name of the class being represented
- * @param id Bean name/id (if any) of this configuration class. used only in the case
- * of XML integration where {@link Configuration} beans may have a
- * user-specified id.
- * @param metadata Configuration annotation resident on this class. May be null indicating
- * that the user specified this class to be processed but failed to properly
- * annotate it.
- * @param modifiers Per {@link java.lang.reflect.Modifier}
- */
- public ConfigurationClass(String name, String id, Configuration metadata, int modifiers) {
- super(name);
- Assert.hasText(name, "Configuration class name must have text");
-
- setBeanName(id);
- setMetadata(metadata);
- setModifiers(modifiers);
- }
-
- public ConfigurationClass addMethod(ModelMethod method) {
- method.setDeclaringClass(this);
- methods.add(method);
- return this;
- }
-
- public String getBeanName() {
- return beanName == null ? getName() : beanName;
- }
-
- public ConfigurationClass setBeanName(String id) {
- this.beanName = id;
- return this;
- }
-
- public Set getMethods() {
- return methods;
- }
-
- public Annotation[] getPluginAnnotations() {
- return pluginAnnotations.toArray(new Annotation[pluginAnnotations.size()]);
- }
-
- /**
- * Add a {@link Extension @Plugin}-annotated annotation to this configuration class.
- *
- * @param pluginAnno type-level Plugin annotation
- */
- public ConfigurationClass addPluginAnnotation(Annotation pluginAnno) {
- pluginAnnotations.add(pluginAnno);
- return this;
- }
-
-
- public ConfigurationClass setDeclaringClass(ConfigurationClass configurationClass) {
- this.declaringClass = configurationClass;
- return this;
- }
-
- public ConfigurationClass getDeclaringClass() {
- return declaringClass;
- }
-
- public int getModifiers() {
- return modifiers;
- }
-
- public ConfigurationClass setModifiers(int modifiers) {
- Assert.isTrue(modifiers >= 0, "modifiers must be non-negative");
- this.modifiers = modifiers;
- return this;
- }
-
- public Configuration getMetadata() {
- return this.metadata;
- }
-
- public ConfigurationClass setMetadata(Configuration configAnno) {
- this.metadata = configAnno;
- return this;
- }
-
- public void validate(List errors) {
-
- // configuration classes must be annotated with @Configuration
- if (metadata == null)
- errors.add(new NonAnnotatedConfigurationError());
-
- // a configuration class may not be final (CGLIB limitation)
- if (Modifier.isFinal(modifiers))
- errors.add(new FinalConfigurationError());
-
- for(ModelMethod method : methods)
- method.validate(errors);
- }
-
-
- @Override
- public String toString() {
- return format("%s; modifiers=%d; methods=%s",
- super.toString(), modifiers, methods);
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = super.hashCode();
- result = prime * result + ((declaringClass == null) ? 0 : declaringClass.hashCode());
- result = prime * result + ((beanName == null) ? 0 : beanName.hashCode());
- result = prime * result + ((metadata == null) ? 0 : metadata.hashCode());
- result = prime * result + ((methods == null) ? 0 : methods.hashCode());
- result = prime * result + modifiers;
- result = prime * result + ((pluginAnnotations == null) ? 0 : pluginAnnotations.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (!super.equals(obj))
- return false;
- if (getClass() != obj.getClass())
- return false;
- ConfigurationClass other = (ConfigurationClass) obj;
- if (declaringClass == null) {
- if (other.declaringClass != null)
- return false;
- } else if (!declaringClass.equals(other.declaringClass))
- return false;
- if (beanName == null) {
- if (other.beanName != null)
- return false;
- } else if (!beanName.equals(other.beanName))
- return false;
- if (metadata == null) {
- if (other.metadata != null)
- return false;
- } else if (!metadata.equals(other.metadata))
- return false;
- if (methods == null) {
- if (other.methods != null)
- return false;
- } else if (!methods.equals(other.methods))
- return false;
- if (modifiers != other.modifiers)
- return false;
- if (pluginAnnotations == null) {
- if (other.pluginAnnotations != null)
- return false;
- } else if (!pluginAnnotations.equals(other.pluginAnnotations))
- return false;
- return true;
- }
-
-
- /** Configuration classes must be annotated with {@link Configuration @Configuration}. */
- public class NonAnnotatedConfigurationError extends UsageError {
- public NonAnnotatedConfigurationError() {
- super(ConfigurationClass.this, -1);
- }
-
- @Override
- public String getDescription() {
- return format("%s was provided as a Java Configuration class but was not annotated with @%s. "
- + "Update the class definition to continue.",
- getSimpleName(), Configuration.class.getSimpleName());
- }
- }
-
- /** Configuration classes must be non-final to accommodate CGLIB subclassing. */
- public class FinalConfigurationError extends UsageError {
- public FinalConfigurationError() {
- super(ConfigurationClass.this, -1);
- }
-
- @Override
- public String getDescription() {
- return format("@%s class may not be final. Remove the final modifier to continue.",
- Configuration.class.getSimpleName());
- }
- }
-
-
- public class InvalidPluginException extends UsageError {
-
- private final Annotation invalidPluginAnnotation;
-
- public InvalidPluginException(Annotation invalidPluginAnnotation) {
- super(ConfigurationClass.this, -1);
- this.invalidPluginAnnotation = invalidPluginAnnotation;
- }
-
- @Override
- public String getDescription() {
- return format("Annotation [%s] was not annotated with @Plugin", invalidPluginAnnotation);
- }
-
- }
-
- /**
- * Error raised when a Bean marked as 'allowOverriding=false' is attempted to be overridden by
- * another bean definition.
- *
- * @see Bean#allowOverriding()
- */
- public class IllegalBeanOverrideError extends UsageError {
- private final ConfigurationClass authoritativeClass;
- private final ModelMethod finalMethodInQuestion;
-
- /**
- * Creates a new IllegalBeanOverrideError object.
- *
- * @param violatingClass class attempting an illegal override. null value signifies
- * that the violating class is unknown or that there is no
- * class to speak of (in the case of an XML bean definition
- * doing the illegal overriding)
- * @param finalMethodInQuestion the method that has been marked 'allowOverriding=false'
- */
- public IllegalBeanOverrideError(ConfigurationClass violatingClass,
- ModelMethod finalMethodInQuestion) {
- super(violatingClass, -1);
- this.authoritativeClass = ConfigurationClass.this;
- this.finalMethodInQuestion = finalMethodInQuestion;
- }
-
- @Override
- public String getDescription() {
- return format("Illegal attempt by '%s' to override bean definition originally "
- + "specified by %s.%s. Consider removing 'allowOverride=false' from original method.",
- finalMethodInQuestion.getName(), authoritativeClass.getSimpleName(),
- finalMethodInQuestion.getName());
- }
- }
-
- public boolean hasMethod(String methodName) {
- return getMethod(methodName) != null;
- }
-
- public ModelMethod getMethod(String methodName) {
-
- for(ModelMethod method : methods)
- if(methodName.equals(method.getName()))
- return method;
-
- return null;
- }
+ private String beanName;
+
+ private int modifiers;
+
+ private Configuration metadata;
+
+ private HashSet methods = new HashSet();
+
+ private HashSet pluginAnnotations = new HashSet();
+
+ private ConfigurationClass declaringClass;
+
+ public ConfigurationClass() {
+ }
+
+ // TODO: get rid of constructors used only for testing. put in testing util.
+ /**
+ * Creates a new ConfigurationClass named className.
+ *
+ * @param name fully-qualified Configuration class being represented
+ *
+ * @see #setClassName(String)
+ */
+ ConfigurationClass(String name) {
+ this(name, null, defaultAnnotation(), 0);
+ }
+
+ ConfigurationClass(String name, Configuration metadata) {
+ this(name, null, metadata, 0);
+ }
+
+ ConfigurationClass(String name, int modifiers) {
+ this(name, null, defaultAnnotation(), modifiers);
+ }
+
+ private static Configuration defaultAnnotation() {
+ @Configuration
+ class Prototype {
+ }
+ return Prototype.class.getAnnotation(Configuration.class);
+ }
+
+ /**
+ * Creates a new ConfigurationClass object.
+ *
+ * @param name Fully qualified name of the class being represented
+ * @param id Bean name/id (if any) of this configuration class. used only in the case of
+ * XML integration where {@link Configuration} beans may have a user-specified
+ * id.
+ * @param metadata Configuration annotation resident on this class. May be null
+ * indicating that the user specified this class to be processed but failed to
+ * properly annotate it.
+ * @param modifiers Per {@link java.lang.reflect.Modifier}
+ */
+ public ConfigurationClass(String name, String id, Configuration metadata, int modifiers) {
+ super(name);
+ Assert.hasText(name, "Configuration class name must have text");
+
+ setBeanName(id);
+ setMetadata(metadata);
+ setModifiers(modifiers);
+ }
+
+ public ConfigurationClass addMethod(ModelMethod method) {
+ method.setDeclaringClass(this);
+ methods.add(method);
+ return this;
+ }
+
+ public String getBeanName() {
+ return beanName == null ? getName() : beanName;
+ }
+
+ public ConfigurationClass setBeanName(String id) {
+ this.beanName = id;
+ return this;
+ }
+
+ public Set getMethods() {
+ return methods;
+ }
+
+ public Annotation[] getPluginAnnotations() {
+ return pluginAnnotations.toArray(new Annotation[pluginAnnotations.size()]);
+ }
+
+ /**
+ * Add a {@link Extension @Plugin}-annotated annotation to this configuration class.
+ *
+ * @param pluginAnno type-level Plugin annotation
+ */
+ public ConfigurationClass addPluginAnnotation(Annotation pluginAnno) {
+ pluginAnnotations.add(pluginAnno);
+ return this;
+ }
+
+
+ public ConfigurationClass setDeclaringClass(ConfigurationClass configurationClass) {
+ this.declaringClass = configurationClass;
+ return this;
+ }
+
+ public ConfigurationClass getDeclaringClass() {
+ return declaringClass;
+ }
+
+ public int getModifiers() {
+ return modifiers;
+ }
+
+ public ConfigurationClass setModifiers(int modifiers) {
+ Assert.isTrue(modifiers >= 0, "modifiers must be non-negative");
+ this.modifiers = modifiers;
+ return this;
+ }
+
+ public Configuration getMetadata() {
+ return this.metadata;
+ }
+
+ public ConfigurationClass setMetadata(Configuration configAnno) {
+ this.metadata = configAnno;
+ return this;
+ }
+
+ public void validate(List errors) {
+
+ // configuration classes must be annotated with @Configuration
+ if (metadata == null)
+ errors.add(new NonAnnotatedConfigurationError());
+
+ // a configuration class may not be final (CGLIB limitation)
+ if (Modifier.isFinal(modifiers))
+ errors.add(new FinalConfigurationError());
+
+ for (ModelMethod method : methods)
+ method.validate(errors);
+ }
+
+
+ @Override
+ public String toString() {
+ return format("%s; modifiers=%d; methods=%s", super.toString(), modifiers, methods);
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + ((declaringClass == null) ? 0 : declaringClass.hashCode());
+ result = prime * result + ((beanName == null) ? 0 : beanName.hashCode());
+ result = prime * result + ((metadata == null) ? 0 : metadata.hashCode());
+ result = prime * result + ((methods == null) ? 0 : methods.hashCode());
+ result = prime * result + modifiers;
+ result = prime * result + ((pluginAnnotations == null) ? 0 : pluginAnnotations.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ ConfigurationClass other = (ConfigurationClass) obj;
+ if (declaringClass == null) {
+ if (other.declaringClass != null)
+ return false;
+ } else if (!declaringClass.equals(other.declaringClass))
+ return false;
+ if (beanName == null) {
+ if (other.beanName != null)
+ return false;
+ } else if (!beanName.equals(other.beanName))
+ return false;
+ if (metadata == null) {
+ if (other.metadata != null)
+ return false;
+ } else if (!metadata.equals(other.metadata))
+ return false;
+ if (methods == null) {
+ if (other.methods != null)
+ return false;
+ } else if (!methods.equals(other.methods))
+ return false;
+ if (modifiers != other.modifiers)
+ return false;
+ if (pluginAnnotations == null) {
+ if (other.pluginAnnotations != null)
+ return false;
+ } else if (!pluginAnnotations.equals(other.pluginAnnotations))
+ return false;
+ return true;
+ }
+
+
+ /** Configuration classes must be annotated with {@link Configuration @Configuration}. */
+ public class NonAnnotatedConfigurationError extends UsageError {
+ public NonAnnotatedConfigurationError() {
+ super(ConfigurationClass.this, -1);
+ }
+
+ @Override
+ public String getDescription() {
+ return format("%s was provided as a Java Configuration class but was not annotated with @%s. "
+ + "Update the class definition to continue.", getSimpleName(), Configuration.class
+ .getSimpleName());
+ }
+ }
+
+ /** Configuration classes must be non-final to accommodate CGLIB subclassing. */
+ public class FinalConfigurationError extends UsageError {
+ public FinalConfigurationError() {
+ super(ConfigurationClass.this, -1);
+ }
+
+ @Override
+ public String getDescription() {
+ return format("@%s class may not be final. Remove the final modifier to continue.",
+ Configuration.class.getSimpleName());
+ }
+ }
+
+
+ public class InvalidPluginException extends UsageError {
+
+ private final Annotation invalidPluginAnnotation;
+
+ public InvalidPluginException(Annotation invalidPluginAnnotation) {
+ super(ConfigurationClass.this, -1);
+ this.invalidPluginAnnotation = invalidPluginAnnotation;
+ }
+
+ @Override
+ public String getDescription() {
+ return format("Annotation [%s] was not annotated with @Plugin", invalidPluginAnnotation);
+ }
+
+ }
+
+ /**
+ * Error raised when a Bean marked as 'allowOverriding=false' is attempted to be
+ * overridden by another bean definition.
+ *
+ * @see Bean#allowOverriding()
+ */
+ public class IllegalBeanOverrideError extends UsageError {
+ private final ConfigurationClass authoritativeClass;
+ private final ModelMethod finalMethodInQuestion;
+
+ /**
+ * Creates a new IllegalBeanOverrideError object.
+ *
+ * @param violatingClass class attempting an illegal override. null value signifies
+ * that the violating class is unknown or that there is no class to speak of
+ * (in the case of an XML bean definition doing the illegal overriding)
+ * @param finalMethodInQuestion the method that has been marked
+ * 'allowOverriding=false'
+ */
+ public IllegalBeanOverrideError(ConfigurationClass violatingClass, ModelMethod finalMethodInQuestion) {
+ super(violatingClass, -1);
+ this.authoritativeClass = ConfigurationClass.this;
+ this.finalMethodInQuestion = finalMethodInQuestion;
+ }
+
+ @Override
+ public String getDescription() {
+ return format("Illegal attempt by '%s' to override bean definition originally "
+ + "specified by %s.%s. Consider removing 'allowOverride=false' from original method.",
+ finalMethodInQuestion.getName(), authoritativeClass.getSimpleName(),
+ finalMethodInQuestion.getName());
+ }
+ }
+
+ public boolean hasMethod(String methodName) {
+ return getMethod(methodName) != null;
+ }
+
+ public ModelMethod getMethod(String methodName) {
+
+ for (ModelMethod method : methods)
+ if (methodName.equals(method.getName()))
+ return method;
+
+ return null;
+ }
}
diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/ConfigurationModel.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/ConfigurationModel.java
index 5c813c8a787..337966f7dc0 100644
--- a/org.springframework.config.java/src/main/java/org/springframework/config/java/ConfigurationModel.java
+++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/ConfigurationModel.java
@@ -21,154 +21,157 @@ import java.util.ArrayList;
import java.util.List;
-
/**
- * An abstract representation of a set of user-provided "Configuration classes", usually but not
- * necessarily annotated with {@link Configuration @Configuration}. The model is populated with a
- * {@link org.springframework.config.java.internal.parsing.ConfigurationParser} implementation which
- * may be reflection-based or ASM-based. Once a model has been populated, it can then be rendered
- * out to a set of BeanDefinitions. The model provides an important layer of indirection between the
- * complexity of parsing a set of classes and the complexity of representing the contents of those
- * classes as BeanDefinitions.
- *
- *
Interface follows the builder pattern for method chaining.
- *
- * @author Chris Beams
- * @see org.springframework.config.java.internal.parsing.ConfigurationParser
+ * An abstract representation of a set of user-provided "Configuration classes", usually but
+ * not necessarily annotated with {@link Configuration @Configuration}. The model is
+ * populated with a
+ * {@link org.springframework.config.java.internal.parsing.ConfigurationParser}
+ * implementation which may be reflection-based or ASM-based. Once a model has been
+ * populated, it can then be rendered out to a set of BeanDefinitions. The model provides an
+ * important layer of indirection between the complexity of parsing a set of classes and the
+ * complexity of representing the contents of those classes as BeanDefinitions.
+ *
+ *
+ * Interface follows the builder pattern for method chaining.
+ *
+ *
+ * @author Chris Beams
+ * @see org.springframework.config.java.internal.parsing.ConfigurationParser
*/
public final class ConfigurationModel implements Validatable {
- /* list is used because order and collection equality matters. */
- private final ArrayList configurationClasses = new ArrayList();
- private final ArrayList validators = new ArrayList();
-
- /**
- * Add a {@link Configuration @Configuration} class to the model. Classes may be added at will
- * and without any particular validation. Malformed classes will be caught and errors processed
- * during {@link #validate() validation}
- *
- * @param configurationClass user-supplied Configuration class
- */
- public ConfigurationModel add(ConfigurationClass configurationClass) {
- configurationClasses.add(configurationClass);
- return this;
- }
-
- public void registerValidator(Validator validator) {
- validators.add(validator);
- }
-
- /**
- * Return configuration classes that have been directly added to this model.
- *
- * @see #getAllConfigurationClasses()
- */
- public ConfigurationClass[] getConfigurationClasses() {
- return configurationClasses.toArray(new ConfigurationClass[] { });
- }
-
-// /**
-// * Return all configuration classes, including all imported configuration classes. This method
-// * should be generally preferred over {@link #getConfigurationClasses()}
-// *
-// * @see #getConfigurationClasses()
-// */
-// public ConfigurationClass[] getAllConfigurationClasses() {
-// ArrayList allConfigClasses = new ArrayList();
-//
-// for (ConfigurationClass configClass : configurationClasses)
-// allConfigClasses.addAll(configClass.getSelfAndAllImports());
-//
-// return allConfigClasses.toArray(new ConfigurationClass[allConfigClasses.size()]);
-// }
-
- public ConfigurationClass[] getAllConfigurationClasses() {
- return configurationClasses.toArray(new ConfigurationClass[configurationClasses.size()]);
- }
-
- /**
- * Recurses through the model validating each object along the way and aggregating any errors.
- *
- * @see ConfigurationClass#validate(java.util.List)
- * @see ModelMethod#validate(java.util.List)
- * @see Validator
- * @see UsageError
- */
- public void validate(List errors) {
- // user must specify at least one configuration
- if (configurationClasses.isEmpty())
- errors.add(new EmptyModelError());
-
- // cascade through model and allow handlers to register validators
- // depending on where they are registered (with the model, the class, or the method)
- // they will be called directly or indirectly below
- for (ConfigurationClass configClass : getAllConfigurationClasses()) {
- for(ModelMethod method : configClass.getMethods()) {
- for(Validator validator : method.getValidators()) {
- if(validator.supports(method))
- method.registerValidator(validator);
- // TODO: support class-level validation
- // if(validator.supports(configClass))
- // configClass.registerValidator(validator);
- if(validator.supports(this))
- this.registerValidator(validator);
- }
- }
- }
-
- // process any validators registered directly with this model object
- for(Validator validator : validators)
- validator.validate(this, errors);
-
- // each individual configuration class must be well-formed
- // note that each configClass detects usage errors on its imports recursively
- // note that each configClass will recursively process its respective methods
- for (ConfigurationClass configClass : configurationClasses)
- configClass.validate(errors);
- }
-
- @Override
- public String toString() {
- return format("%s: configurationClasses=%s",
- getClass().getSimpleName(), configurationClasses);
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((configurationClasses == null) ? 0 : configurationClasses.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- ConfigurationModel other = (ConfigurationModel) obj;
- if (configurationClasses == null) {
- if (other.configurationClasses != null)
- return false;
- } else if (!configurationClasses.equals(other.configurationClasses))
- return false;
- return true;
- }
-
-
- public class EmptyModelError extends UsageError {
- public EmptyModelError() {
- super(null, 0);
- }
-
- @Override
- public String getDescription() {
- return format("Configuration model was empty. Make sure at least one "
- + "@%s class has been specified.", Configuration.class.getSimpleName());
- }
- }
+ /* list is used because order and collection equality matters. */
+ private final ArrayList configurationClasses = new ArrayList();
+ private final ArrayList validators = new ArrayList();
+
+ /**
+ * Add a {@link Configuration @Configuration} class to the model. Classes may be added
+ * at will and without any particular validation. Malformed classes will be caught and
+ * errors processed during {@link #validate() validation}
+ *
+ * @param configurationClass user-supplied Configuration class
+ */
+ public ConfigurationModel add(ConfigurationClass configurationClass) {
+ configurationClasses.add(configurationClass);
+ return this;
+ }
+
+ public void registerValidator(Validator validator) {
+ validators.add(validator);
+ }
+
+ /**
+ * Return configuration classes that have been directly added to this model.
+ *
+ * @see #getAllConfigurationClasses()
+ */
+ public ConfigurationClass[] getConfigurationClasses() {
+ return configurationClasses.toArray(new ConfigurationClass[] {});
+ }
+
+ // /**
+ // * Return all configuration classes, including all imported configuration classes.
+ // This method
+ // * should be generally preferred over {@link #getConfigurationClasses()}
+ // *
+ // * @see #getConfigurationClasses()
+ // */
+ // public ConfigurationClass[] getAllConfigurationClasses() {
+ // ArrayList allConfigClasses = new ArrayList();
+ //
+ // for (ConfigurationClass configClass : configurationClasses)
+ // allConfigClasses.addAll(configClass.getSelfAndAllImports());
+ //
+ // return allConfigClasses.toArray(new ConfigurationClass[allConfigClasses.size()]);
+ // }
+
+ public ConfigurationClass[] getAllConfigurationClasses() {
+ return configurationClasses.toArray(new ConfigurationClass[configurationClasses.size()]);
+ }
+
+ /**
+ * Recurses through the model validating each object along the way and aggregating any
+ * errors.
+ *
+ * @see ConfigurationClass#validate(java.util.List)
+ * @see ModelMethod#validate(java.util.List)
+ * @see Validator
+ * @see UsageError
+ */
+ public void validate(List errors) {
+ // user must specify at least one configuration
+ if (configurationClasses.isEmpty())
+ errors.add(new EmptyModelError());
+
+ // cascade through model and allow handlers to register validators
+ // depending on where they are registered (with the model, the class, or the method)
+ // they will be called directly or indirectly below
+ for (ConfigurationClass configClass : getAllConfigurationClasses()) {
+ for (ModelMethod method : configClass.getMethods()) {
+ for (Validator validator : method.getValidators()) {
+ if (validator.supports(method))
+ method.registerValidator(validator);
+ // TODO: support class-level validation
+ // if(validator.supports(configClass))
+ // configClass.registerValidator(validator);
+ if (validator.supports(this))
+ this.registerValidator(validator);
+ }
+ }
+ }
+
+ // process any validators registered directly with this model object
+ for (Validator validator : validators)
+ validator.validate(this, errors);
+
+ // each individual configuration class must be well-formed
+ // note that each configClass detects usage errors on its imports recursively
+ // note that each configClass will recursively process its respective methods
+ for (ConfigurationClass configClass : configurationClasses)
+ configClass.validate(errors);
+ }
+
+ @Override
+ public String toString() {
+ return format("%s: configurationClasses=%s", getClass().getSimpleName(), configurationClasses);
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((configurationClasses == null) ? 0 : configurationClasses.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ ConfigurationModel other = (ConfigurationModel) obj;
+ if (configurationClasses == null) {
+ if (other.configurationClasses != null)
+ return false;
+ } else if (!configurationClasses.equals(other.configurationClasses))
+ return false;
+ return true;
+ }
+
+
+ public class EmptyModelError extends UsageError {
+ public EmptyModelError() {
+ super(null, 0);
+ }
+
+ @Override
+ public String getDescription() {
+ return format("Configuration model was empty. Make sure at least one "
+ + "@%s class has been specified.", Configuration.class.getSimpleName());
+ }
+ }
}
diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/Factory.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/Factory.java
index bea48c6d2ec..6b0bd567708 100644
--- a/org.springframework.config.java/src/main/java/org/springframework/config/java/Factory.java
+++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/Factory.java
@@ -24,9 +24,10 @@ import java.lang.annotation.Target;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.NoOp;
+
/**
* Meta-annotation used to identify annotations as producers of beans and/or values.
- *
+ *
* @author Chris Beams
*/
@Retention(RetentionPolicy.RUNTIME)
@@ -34,22 +35,21 @@ import net.sf.cglib.proxy.NoOp;
@Documented
public @interface Factory {
- /**
- * Specifies which registrar (if any) should be used to register
- * bean definitions for this {@link Factory} method.
- */
- Class extends BeanDefinitionRegistrar> registrarType();
+ /**
+ * Specifies which registrar (if any) should be used to register bean definitions for
+ * this {@link Factory} method.
+ */
+ Class extends BeanDefinitionRegistrar> registrarType();
- /**
- * Specifies what (if any) callback should be used when processing this {@link Factory} method.
- * Defaults to CGLIB's {@link NoOp}, which does nothing.
- * TODO: rename (interceptorType)? to keep with the -or|-ar nomenclature
- */
- Class extends Callback> callbackType() default NoOp.class;
+ /**
+ * Specifies what (if any) callback should be used when processing this {@link Factory}
+ * method. Defaults to CGLIB's {@link NoOp}, which does nothing. TODO: rename
+ * (interceptorType)? to keep with the -or|-ar nomenclature
+ */
+ Class extends Callback> callbackType() default NoOp.class;
- /**
- * TODO: document
- * TODO: rename
- */
- Class extends Validator>[] validatorTypes() default {};
+ /**
+ * TODO: document TODO: rename
+ */
+ Class extends Validator>[] validatorTypes() default {};
}
diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/MalformedConfigurationException.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/MalformedConfigurationException.java
index ba3e2a2c939..4fda73f97b8 100644
--- a/org.springframework.config.java/src/main/java/org/springframework/config/java/MalformedConfigurationException.java
+++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/MalformedConfigurationException.java
@@ -22,54 +22,54 @@ import java.util.List;
/**
* TODO: rename to UsageException / move outside .internal?
- *
- * @author Chris Beams
+ *
+ * @author Chris Beams
*/
@SuppressWarnings("serial")
public class MalformedConfigurationException extends RuntimeException {
- private final List extends UsageError> errors;
+ private final List extends UsageError> errors;
- public MalformedConfigurationException(String message) {
- super(message);
- this.errors = new ArrayList();
- }
+ public MalformedConfigurationException(String message) {
+ super(message);
+ this.errors = new ArrayList();
+ }
- public MalformedConfigurationException(UsageError... errors) {
- super(toString(errors));
- this.errors = Arrays.asList(errors);
- }
+ public MalformedConfigurationException(UsageError... errors) {
+ super(toString(errors));
+ this.errors = Arrays.asList(errors);
+ }
- public boolean containsError(Class extends UsageError> errorType) {
- for (UsageError error : errors)
- if (error.getClass().isAssignableFrom(errorType))
- return true;
+ public boolean containsError(Class extends UsageError> errorType) {
+ for (UsageError error : errors)
+ if (error.getClass().isAssignableFrom(errorType))
+ return true;
- return false;
- }
+ return false;
+ }
- /**
- * Render a list of syntax errors as output suitable for diagnosis via System.err.
- */
- private static String toString(UsageError... errors) {
- StringBuilder sb = new StringBuilder();
+ /**
+ * Render a list of syntax errors as output suitable for diagnosis via System.err.
+ */
+ private static String toString(UsageError... errors) {
+ StringBuilder sb = new StringBuilder();
- sb.append("\n");
+ sb.append("\n");
- if (errors.length == 1)
- sb.append("A usage error has ");
- else
- sb.append(errors.length + " usage errors have ");
+ if (errors.length == 1)
+ sb.append("A usage error has ");
+ else
+ sb.append(errors.length + " usage errors have ");
- sb.append("been detected:\n");
+ sb.append("been detected:\n");
- for (int i = 0; i < errors.length; i++) {
- sb.append(errors[i].toString());
- if ((i + 1) < errors.length)
- sb.append('\n');
- }
+ for (int i = 0; i < errors.length; i++) {
+ sb.append(errors[i].toString());
+ if ((i + 1) < errors.length)
+ sb.append('\n');
+ }
- return sb.toString();
- }
+ return sb.toString();
+ }
}
diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/ModelClass.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/ModelClass.java
index 5f7fcc657b8..589014f6640 100644
--- a/org.springframework.config.java/src/main/java/org/springframework/config/java/ModelClass.java
+++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/ModelClass.java
@@ -21,139 +21,141 @@ import org.springframework.util.ClassUtils;
/**
- * Abstract representation of a class, free from java reflection.
- * Base class used within the internal JavaConfig metamodel for
- * representing {@link Configuration} classes.
- *
+ * Abstract representation of a class, free from java reflection. Base class used within the
+ * internal JavaConfig metamodel for representing {@link Configuration} classes.
+ *
* @author Chris Beams
*/
// TODO: Consider eliminating in favor of just ConfigurationClass
public class ModelClass implements BeanMetadataElement {
- private String name;
- private boolean isInterface;
- private String source;
-
- /**
- * Creates a new and empty ModelClass instance.
- */
- public ModelClass() { }
-
- /**
- * Creates a new ModelClass instance
- *
- * @param name fully-qualified name of the class being represented
- */
- public ModelClass(String name) {
- this(name, false);
- }
-
- /**
- * Creates a new ModelClass instance
- *
- * @param name fully-qualified name of the class being represented
- * @param isInterface whether the represented type is an interface
- */
- public ModelClass(String name, boolean isInterface) {
- this.name = name;
- this.isInterface = isInterface;
- }
-
- /**
- * Returns the fully-qualified name of this class.
- */
- public String getName() {
- return name;
- }
-
- /**
- * Sets the fully-qualified name of this class.
- */
- public void setName(String className) {
- this.name = className;
- }
-
- /**
- * Returns the non-qualified name of this class. Given com.acme.Foo, returns 'Foo'.
- */
- public String getSimpleName() {
- return name == null ? null : ClassUtils.getShortName(name);
- }
-
- /**
- * Returns whether the class represented by this ModelClass instance is an interface.
- */
- public boolean isInterface() {
- return isInterface;
- }
-
- /**
- * Signifies that this class is (true) or is not (false) an interface.
- */
- public void setInterface(boolean isInterface) {
- this.isInterface = isInterface;
- }
-
- /**
- * Returns a resource path-formatted representation of the .java
- * file that declares this class
- */
- public String getSource() {
- return source;
- }
-
- /**
- * Set the source location for this class. Must be a resource-path formatted string.
- *
- * @param source resource path to the .java file that declares this class.
- */
- public void setSource(Object source) {
- Assert.isInstanceOf(String.class, source);
- this.source = (String) source;
- }
-
- /**
- * Given a ModelClass instance representing a class com.acme.Foo, this method will return
- *
- * ModelClass: name=Foo
- *
- */
- @Override
- public String toString() {
- return String.format("%s: name=%s", getClass().getSimpleName(), getSimpleName());
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = (prime * result) + (isInterface ? 1231 : 1237);
- result = (prime * result) + ((name == null) ? 0 : name.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
-
- if (obj == null)
- return false;
-
- if (getClass() != obj.getClass())
- return false;
-
- ModelClass other = (ModelClass) obj;
- if (isInterface != other.isInterface)
- return false;
-
- if (name == null) {
- if (other.name != null)
- return false;
- } else if (!name.equals(other.name))
- return false;
-
- return true;
- }
+ private String name;
+ private boolean isInterface;
+ private String source;
+
+ /**
+ * Creates a new and empty ModelClass instance.
+ */
+ public ModelClass() {
+ }
+
+ /**
+ * Creates a new ModelClass instance
+ *
+ * @param name fully-qualified name of the class being represented
+ */
+ public ModelClass(String name) {
+ this(name, false);
+ }
+
+ /**
+ * Creates a new ModelClass instance
+ *
+ * @param name fully-qualified name of the class being represented
+ * @param isInterface whether the represented type is an interface
+ */
+ public ModelClass(String name, boolean isInterface) {
+ this.name = name;
+ this.isInterface = isInterface;
+ }
+
+ /**
+ * Returns the fully-qualified name of this class.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets the fully-qualified name of this class.
+ */
+ public void setName(String className) {
+ this.name = className;
+ }
+
+ /**
+ * Returns the non-qualified name of this class. Given com.acme.Foo, returns 'Foo'.
+ */
+ public String getSimpleName() {
+ return name == null ? null : ClassUtils.getShortName(name);
+ }
+
+ /**
+ * Returns whether the class represented by this ModelClass instance is an interface.
+ */
+ public boolean isInterface() {
+ return isInterface;
+ }
+
+ /**
+ * Signifies that this class is (true) or is not (false) an interface.
+ */
+ public void setInterface(boolean isInterface) {
+ this.isInterface = isInterface;
+ }
+
+ /**
+ * Returns a resource path-formatted representation of the .java file that declares this
+ * class
+ */
+ public String getSource() {
+ return source;
+ }
+
+ /**
+ * Set the source location for this class. Must be a resource-path formatted string.
+ *
+ * @param source resource path to the .java file that declares this class.
+ */
+ public void setSource(Object source) {
+ Assert.isInstanceOf(String.class, source);
+ this.source = (String) source;
+ }
+
+ /**
+ * Given a ModelClass instance representing a class com.acme.Foo, this method will
+ * return
+ *
+ *
+ * ModelClass: name=Foo
+ *
+ */
+ @Override
+ public String toString() {
+ return String.format("%s: name=%s", getClass().getSimpleName(), getSimpleName());
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = (prime * result) + (isInterface ? 1231 : 1237);
+ result = (prime * result) + ((name == null) ? 0 : name.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+
+ if (obj == null)
+ return false;
+
+ if (getClass() != obj.getClass())
+ return false;
+
+ ModelClass other = (ModelClass) obj;
+ if (isInterface != other.isInterface)
+ return false;
+
+ if (name == null) {
+ if (other.name != null)
+ return false;
+ } else if (!name.equals(other.name))
+ return false;
+
+ return true;
+ }
}
diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/ModelMethod.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/ModelMethod.java
index d5b667cc83a..2f53c73ac68 100644
--- a/org.springframework.config.java/src/main/java/org/springframework/config/java/ModelMethod.java
+++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/ModelMethod.java
@@ -34,207 +34,206 @@ import org.springframework.util.Assert;
/** TODO: JAVADOC */
public final class ModelMethod implements Validatable {
- private final String name;
- private final int modifiers;
- private final ModelClass returnType;
- private final List annotations = new ArrayList();
- private transient ConfigurationClass declaringClass;
- private transient int lineNumber;
- private transient Factory factoryAnno;
- private transient final List validators = new ArrayList();
-
- public ModelMethod(String name, int modifiers, ModelClass returnType, Annotation... annotations) {
- Assert.hasText(name);
- this.name = name;
-
- Assert.notNull(annotations);
- for(Annotation annotation : annotations) {
- this.annotations.add(annotation);
- if(factoryAnno == null)
- factoryAnno = annotation.annotationType().getAnnotation(Factory.class);
- }
-
- Assert.isTrue(modifiers >= 0, "modifiers must be non-negative: " + modifiers);
- this.modifiers = modifiers;
-
- Assert.notNull(returnType);
- this.returnType = returnType;
- }
-
- public String getName() {
- return name;
- }
-
- public ModelClass getReturnType() {
- return returnType;
- }
-
- /**
- * @see java.lang.reflect.Modifier
- */
- public int getModifiers() {
- return modifiers;
- }
-
- /**
- * Returns the annotation on this method matching annoType or null
- * IllegalStateException} if not present.
- *
- * @see #getRequiredAnnotation(Class)
- */
- @SuppressWarnings("unchecked")
- public T getAnnotation(Class annoType) {
- for(Annotation anno : annotations)
- if(anno.annotationType().equals(annoType))
- return (T) anno;
-
- return null;
- }
-
- /**
- * Returns the annotation on this method matching annoType or throws
- * {@link IllegalStateException} if not present.
- *
- * @see #getAnnotation(Class)
- */
- public T getRequiredAnnotation(Class annoType) {
- T anno = getAnnotation(annoType);
-
- if(anno == null)
- throw new IllegalStateException(
- format("annotation %s not found on %s", annoType.getSimpleName(), this));
-
- return anno;
- }
-
- /**
- * Sets up bi-directional relationship between this method and its declaring class.
- *
- * @see ConfigurationClass#addMethod(ModelMethod)
- */
- public void setDeclaringClass(ConfigurationClass declaringClass) {
- this.declaringClass = declaringClass;
- }
-
- public ConfigurationClass getDeclaringClass() {
- return declaringClass;
- }
-
- public void setLineNumber(int lineNumber) {
- this.lineNumber = lineNumber;
- }
-
- public int getLineNumber() {
- return lineNumber;
- }
-
- public void registerValidator(Validator validator) {
- validators.add(validator);
- }
-
- public void validate(List errors) {
- for(Validator validator : validators)
- validator.validate(this, errors);
-
- if (Modifier.isPrivate(getModifiers()))
- errors.add(new PrivateMethodError());
-
- if (Modifier.isFinal(getModifiers()))
- errors.add(new FinalMethodError());
- }
-
- public BeanDefinitionRegistrar getRegistrar() {
- return getInstance(factoryAnno.registrarType());
- }
-
- public Set getValidators() {
- HashSet validator = new HashSet();
-
- for(Class extends Validator> validatorType : factoryAnno.validatorTypes())
- validator.add(getInstance(validatorType));
-
- return validator;
- }
-
- public Callback getCallback() {
- Class extends Callback> callbackType = factoryAnno.callbackType();
-
- if(callbackType.equals(NoOp.class))
- return NoOp.INSTANCE;
-
- return getInstance(callbackType);
- }
-
- @Override
- public String toString() {
- String returnTypeName = returnType == null ? "" : returnType.getSimpleName();
- return String.format("%s: name=%s; returnType=%s; modifiers=%d",
- getClass().getSimpleName(), name, returnTypeName, modifiers);
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((annotations == null) ? 0 : annotations.hashCode());
- result = prime * result + modifiers;
- result = prime * result + ((name == null) ? 0 : name.hashCode());
- result = prime * result + ((returnType == null) ? 0 : returnType.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- ModelMethod other = (ModelMethod) obj;
- if (annotations == null) {
- if (other.annotations != null)
- return false;
- } else if (!annotations.equals(other.annotations))
- return false;
- if (modifiers != other.modifiers)
- return false;
- if (name == null) {
- if (other.name != null)
- return false;
- } else if (!name.equals(other.name))
- return false;
- if (returnType == null) {
- if (other.returnType != null)
- return false;
- } else if (!returnType.equals(other.returnType))
- return false;
- return true;
- }
-
- /** JavaConfigMethods must be visible (non-private) in order to accommodate CGLIB. */
- public class PrivateMethodError extends UsageError {
- public PrivateMethodError() {
- super(getDeclaringClass(), getLineNumber());
- }
-
- @Override
- public String getDescription() {
- return format("method '%s' may not be private", getName());
- }
- }
-
- /** JavaConfigMethods must be extensible (non-final) in order to accommodate CGLIB. */
- public class FinalMethodError extends UsageError {
- public FinalMethodError() {
- super(getDeclaringClass(), getLineNumber());
- }
-
- @Override
- public String getDescription() {
- return format("method '%s' may not be final - remove the final modifier to continue",
- getName());
- }
- }
-
+ private final String name;
+ private final int modifiers;
+ private final ModelClass returnType;
+ private final List annotations = new ArrayList();
+ private transient ConfigurationClass declaringClass;
+ private transient int lineNumber;
+ private transient Factory factoryAnno;
+ private transient final List validators = new ArrayList();
+
+ public ModelMethod(String name, int modifiers, ModelClass returnType, Annotation... annotations) {
+ Assert.hasText(name);
+ this.name = name;
+
+ Assert.notNull(annotations);
+ for (Annotation annotation : annotations) {
+ this.annotations.add(annotation);
+ if (factoryAnno == null)
+ factoryAnno = annotation.annotationType().getAnnotation(Factory.class);
+ }
+
+ Assert.isTrue(modifiers >= 0, "modifiers must be non-negative: " + modifiers);
+ this.modifiers = modifiers;
+
+ Assert.notNull(returnType);
+ this.returnType = returnType;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public ModelClass getReturnType() {
+ return returnType;
+ }
+
+ /**
+ * @see java.lang.reflect.Modifier
+ */
+ public int getModifiers() {
+ return modifiers;
+ }
+
+ /**
+ * Returns the annotation on this method matching annoType or null
+ * IllegalStateException} if not present.
+ *
+ * @see #getRequiredAnnotation(Class)
+ */
+ @SuppressWarnings("unchecked")
+ public T getAnnotation(Class annoType) {
+ for (Annotation anno : annotations)
+ if (anno.annotationType().equals(annoType))
+ return (T) anno;
+
+ return null;
+ }
+
+ /**
+ * Returns the annotation on this method matching annoType or throws
+ * {@link IllegalStateException} if not present.
+ *
+ * @see #getAnnotation(Class)
+ */
+ public T getRequiredAnnotation(Class annoType) {
+ T anno = getAnnotation(annoType);
+
+ if (anno == null)
+ throw new IllegalStateException(format("annotation %s not found on %s", annoType.getSimpleName(),
+ this));
+
+ return anno;
+ }
+
+ /**
+ * Sets up bi-directional relationship between this method and its declaring class.
+ *
+ * @see ConfigurationClass#addMethod(ModelMethod)
+ */
+ public void setDeclaringClass(ConfigurationClass declaringClass) {
+ this.declaringClass = declaringClass;
+ }
+
+ public ConfigurationClass getDeclaringClass() {
+ return declaringClass;
+ }
+
+ public void setLineNumber(int lineNumber) {
+ this.lineNumber = lineNumber;
+ }
+
+ public int getLineNumber() {
+ return lineNumber;
+ }
+
+ public void registerValidator(Validator validator) {
+ validators.add(validator);
+ }
+
+ public void validate(List errors) {
+ for (Validator validator : validators)
+ validator.validate(this, errors);
+
+ if (Modifier.isPrivate(getModifiers()))
+ errors.add(new PrivateMethodError());
+
+ if (Modifier.isFinal(getModifiers()))
+ errors.add(new FinalMethodError());
+ }
+
+ public BeanDefinitionRegistrar getRegistrar() {
+ return getInstance(factoryAnno.registrarType());
+ }
+
+ public Set getValidators() {
+ HashSet validator = new HashSet();
+
+ for (Class extends Validator> validatorType : factoryAnno.validatorTypes())
+ validator.add(getInstance(validatorType));
+
+ return validator;
+ }
+
+ public Callback getCallback() {
+ Class extends Callback> callbackType = factoryAnno.callbackType();
+
+ if (callbackType.equals(NoOp.class))
+ return NoOp.INSTANCE;
+
+ return getInstance(callbackType);
+ }
+
+ @Override
+ public String toString() {
+ String returnTypeName = returnType == null ? "" : returnType.getSimpleName();
+ return String.format("%s: name=%s; returnType=%s; modifiers=%d", getClass().getSimpleName(), name,
+ returnTypeName, modifiers);
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((annotations == null) ? 0 : annotations.hashCode());
+ result = prime * result + modifiers;
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ result = prime * result + ((returnType == null) ? 0 : returnType.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ ModelMethod other = (ModelMethod) obj;
+ if (annotations == null) {
+ if (other.annotations != null)
+ return false;
+ } else if (!annotations.equals(other.annotations))
+ return false;
+ if (modifiers != other.modifiers)
+ return false;
+ if (name == null) {
+ if (other.name != null)
+ return false;
+ } else if (!name.equals(other.name))
+ return false;
+ if (returnType == null) {
+ if (other.returnType != null)
+ return false;
+ } else if (!returnType.equals(other.returnType))
+ return false;
+ return true;
+ }
+
+ /** JavaConfigMethods must be visible (non-private) in order to accommodate CGLIB. */
+ public class PrivateMethodError extends UsageError {
+ public PrivateMethodError() {
+ super(getDeclaringClass(), getLineNumber());
+ }
+
+ @Override
+ public String getDescription() {
+ return format("method '%s' may not be private", getName());
+ }
+ }
+
+ /** JavaConfigMethods must be extensible (non-final) in order to accommodate CGLIB. */
+ public class FinalMethodError extends UsageError {
+ public FinalMethodError() {
+ super(getDeclaringClass(), getLineNumber());
+ }
+
+ @Override
+ public String getDescription() {
+ return format("method '%s' may not be final - remove the final modifier to continue", getName());
+ }
+ }
+
}
diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/Scopes.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/Scopes.java
index 1b0636c9b1b..18782484f41 100644
--- a/org.springframework.config.java/src/main/java/org/springframework/config/java/Scopes.java
+++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/Scopes.java
@@ -19,23 +19,24 @@ package org.springframework.config.java;
/**
* Enumerates the names of the scopes supported out of the box in Spring.
*
- * Not modeled as an actual java enum because annotations that accept a scope
- * attribute must allow for user-defined scope names. Given that java
- * enums are not extensible, these must remain simple string constants.
- *
- * @author Chris Beams
+ * Not modeled as an actual java enum because annotations that accept a scope attribute must
+ * allow for user-defined scope names. Given that java enums are not extensible, these must
+ * remain simple string constants.
+ *
+ * @author Chris Beams
* @since 3.0
*/
public class Scopes {
-
- private Scopes() { }
- public static final String SINGLETON = "singleton"; // see BeanDefinition.SCOPE_SINGLETON;
+ private Scopes() {
+ }
+
+ public static final String SINGLETON = "singleton";
- public static final String PROTOTYPE = "prototype"; // see BeanDefinition.SCOPE_PROTOTYPE;
+ public static final String PROTOTYPE = "prototype";
- public static final String REQUEST = "request"; // see WebApplicationContext.SCOPE_REQUEST;
+ public static final String REQUEST = "request";
- public static final String SESSION = "session"; // see WebApplicationContext.SCOPE_SESSION;
+ public static final String SESSION = "session";
}
diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/UsageError.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/UsageError.java
index 43b0f78ec90..d7d9122d1a0 100644
--- a/org.springframework.config.java/src/main/java/org/springframework/config/java/UsageError.java
+++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/UsageError.java
@@ -16,57 +16,58 @@
package org.springframework.config.java;
-
/**
- * Represents an invalid usage of JavaConfig constructs, e.g. a {@link Configuration} that declares
- * no {@link Bean @Bean} methods, or declaring both {@link Bean @Bean} and
- * {@link ExternalBean @ExternalBean} on a single method. Explore the type hierarchy to discover all
- * possible usage errors.
- *
- * @author Chris Beams
- * @see MalformedConfigurationException
+ * Represents an invalid usage of JavaConfig constructs, e.g. a {@link Configuration} that
+ * declares no {@link Bean @Bean} methods, or declaring both {@link Bean @Bean} and
+ * {@link ExternalBean @ExternalBean} on a single method. Explore the type hierarchy to
+ * discover all possible usage errors.
+ *
+ * @author Chris Beams
+ * @see MalformedConfigurationException
*/
public abstract class UsageError {
- private final ModelClass clazz;
- private final int lineNumber;
+ private final ModelClass clazz;
+ private final int lineNumber;
- /**
- * Create a new usage error, providing information about where the error was detected.
- *
- * @param modelClass class in which this error was detected. Null value indicates that the
- * error was not local to a single class.
- * @param lineNumber line number on which this error was detected (useful for tooling integration)
- *
- * @see ModelClass#getSource()
- */
- public UsageError(ModelClass modelClass, int lineNumber) {
- this.clazz = modelClass;
- this.lineNumber = lineNumber;
- }
+ /**
+ * Create a new usage error, providing information about where the error was detected.
+ *
+ * @param modelClass class in which this error was detected. Null value indicates that
+ * the error was not local to a single class.
+ * @param lineNumber line number on which this error was detected (useful for tooling
+ * integration)
+ *
+ * @see ModelClass#getSource()
+ */
+ public UsageError(ModelClass modelClass, int lineNumber) {
+ this.clazz = modelClass;
+ this.lineNumber = lineNumber;
+ }
- /**
- * Human-readable description of this error suitable for console output or IDE tooling.
- */
- public abstract String getDescription();
+ /**
+ * Human-readable description of this error suitable for console output or IDE tooling.
+ */
+ public abstract String getDescription();
- /**
- * Same as {@link #getDescription()} but attributed with class and line number information. If
- * modelClass constructor parameter was null, class and line number information will be omitted.
- */
- public final String getAttributedDescription() {
- if (clazz == null)
- return getDescription();
+ /**
+ * Same as {@link #getDescription()} but attributed with class and line number
+ * information. If modelClass constructor parameter was null, class and line number
+ * information will be omitted.
+ */
+ public final String getAttributedDescription() {
+ if (clazz == null)
+ return getDescription();
- return String.format("%s:%d: %s", clazz.getSource(), lineNumber, getDescription());
- }
+ return String.format("%s:%d: %s", clazz.getSource(), lineNumber, getDescription());
+ }
- /**
- * Delegates directly to {@link #getAttributedDescription()}.
- */
- @Override
- public String toString() {
- return getAttributedDescription();
- }
+ /**
+ * Delegates directly to {@link #getAttributedDescription()}.
+ */
+ @Override
+ public String toString() {
+ return getAttributedDescription();
+ }
}
diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/Util.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/Util.java
index 499f318aa98..d974a920089 100644
--- a/org.springframework.config.java/src/main/java/org/springframework/config/java/Util.java
+++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/Util.java
@@ -14,9 +14,10 @@ import org.springframework.util.ReflectionUtils;
import sun.security.x509.Extension;
+
/**
* Misc utils
- *
+ *
* @author Chris Beams
*/
// TODO: SJC-242 general - check cycles with s101
@@ -25,140 +26,142 @@ import sun.security.x509.Extension;
// TODO: SJC-242 rename, repackage, document
public class Util {
- private static final Log log = LogFactory.getLog(Util.class);
-
- private Util() { }
-
- /**
- * Returns instance of type T by invoking its default or no-arg
- * constructor.
- *
- * Any reflection-related issues are re-thrown as unchecked.
- */
- public static T getInstance(Class extends T> clazz) {
- try {
- Constructor extends T> noArgCtor = clazz.getDeclaredConstructor();
- ReflectionUtils.makeAccessible(noArgCtor);
- return noArgCtor.newInstance();
- } catch (Exception ex) {
- ReflectionUtils.handleReflectionException(ex);
- throw new IllegalStateException(
- format("Unexpected reflection exception - %s: %s",
- ex.getClass().getName(), ex.getMessage()));
- }
- }
-
- /**
- * Loads the specified class using the default class loader, gracefully handling any
- * {@link ClassNotFoundException} that may be thrown. This functionality is specifically
- * implemented to accomodate tooling (Spring IDE) concerns, where user-defined types will not be
- *
- * @param type of class to be returned
- * @param fqClassName fully-qualified class name
- *
- * @return newly loaded class instance, null if class could not be found
- *
- * @see #loadRequiredClass(String)
- * @see #loadToolingSafeClass(String)
- * @see ClassUtils#getDefaultClassLoader()
- */
- @SuppressWarnings("unchecked")
- public static Class extends T> loadClass(String fqClassName) {
- try {
- return (Class extends T>) ClassUtils.getDefaultClassLoader().loadClass(fqClassName);
- } catch (ClassNotFoundException ex) {
- return null;
- }
- }
-
- /**
- * Loads the specified class using the default class loader, rethrowing any
- * {@link ClassNotFoundException} as an unchecked exception.
- *
- * @param type of class to be returned
- * @param fqClassName fully-qualified class name
- *
- * @return newly loaded class instance
- *
- * @throws IllegalArgumentException if configClassName cannot be loaded.
- *
- * @see #loadClass(String)
- * @see #loadToolingSafeClass(String)
- * @see ClassUtils#getDefaultClassLoader()
- */
- @SuppressWarnings("unchecked")
- public static Class extends T> loadRequiredClass(String fqClassName) {
- try {
- return (Class extends T>)getDefaultClassLoader().loadClass(fqClassName);
- } catch (ClassNotFoundException ex) {
- throw new IllegalArgumentException(
- format("Class [%s] could not be loaded, check your CLASSPATH.", fqClassName), ex);
- }
- }
-
- /**
- * Loads the specified class using the default class loader, gracefully handling any
- * {@link ClassNotFoundException} that may be thrown by issuing a WARN level logging statement
- * and return null. This functionality is specifically implemented to accomodate tooling
- * (Spring IDE) concerns, where user-defined types will not be available to the tooling.
- *
- * ASM class reading is used throughout JavaConfig, but there are certain cases where
- * classloading cannot be avoided - specifically in cases where users define their own
- * {@link Extension} or {@link Factory} annotations. This method should therefore be used sparingly
- * but consistently where required.
- *
- * Because {@link ClassNotFoundException} is compensated for by returning null, callers must
- * take care to handle the null case appropriately.
- *
- * In cases where the WARN logging statement is not desired, use the {@link #loadClass(String)}
- * method, which returns null but issues no logging statements.
- *
- * This method should only ever return null in the case of a user-defined type be processed at
- * tooling time. Therefore, tooling may not be able to represent any custom annotation
- * semantics, but JavaConfig itself will not have any problem loading and respecting them at
- * actual runtime.
- *
- * @param type of class to be returned
- * @param fqClassName fully-qualified class name
- *
- * @return newly loaded class, null if class could not be found.
- *
- * @see #loadClass(String)
- * @see #loadRequiredClass(String)
- * @see ClassUtils#getDefaultClassLoader()
- */
- @SuppressWarnings("unchecked")
- public static Class extends T> loadToolingSafeClass(String fqClassName) {
- try {
- return (Class extends T>) ClassUtils.getDefaultClassLoader().loadClass(fqClassName);
- } catch (ClassNotFoundException ex) {
- log.warn(format("Unable to load class [%s], likely due to tooling-specific restrictions."
- + "Attempting to continue, but unexpected errors may occur", fqClassName), ex);
- return null;
- }
- }
-
- /**
- * Uses the default ClassLoader to load pathToClass. Appends '.class'
- * to pathToClass before attempting to load.
- *
- * @param pathToClass resource path to class, not including .class suffix.
- * e.g.: com/acme/MyClass
- *
- * @return inputStream for pathToClass
- *
- * @throws RuntimeException if pathToClass does not exist
- */
- public static InputStream getClassAsStream(String pathToClass) {
- String classFileName = pathToClass + ClassUtils.CLASS_FILE_SUFFIX;
-
- InputStream is = ClassUtils.getDefaultClassLoader().getResourceAsStream(classFileName);
-
- if (is == null)
- throw new RuntimeException(
- new FileNotFoundException("Class file [" + classFileName + "] not found"));
-
- return is;
- }
+ private static final Log log = LogFactory.getLog(Util.class);
+
+ private Util() {
+ }
+
+ /**
+ * Returns instance of type T by invoking its default or no-arg constructor.
+ *
+ * Any reflection-related issues are re-thrown as unchecked.
+ */
+ public static T getInstance(Class extends T> clazz) {
+ try {
+ Constructor extends T> noArgCtor = clazz.getDeclaredConstructor();
+ ReflectionUtils.makeAccessible(noArgCtor);
+ return noArgCtor.newInstance();
+ } catch (Exception ex) {
+ ReflectionUtils.handleReflectionException(ex);
+ throw new IllegalStateException(format("Unexpected reflection exception - %s: %s", ex.getClass()
+ .getName(), ex.getMessage()));
+ }
+ }
+
+ /**
+ * Loads the specified class using the default class loader, gracefully handling any
+ * {@link ClassNotFoundException} that may be thrown. This functionality is specifically
+ * implemented to accomodate tooling (Spring IDE) concerns, where user-defined types
+ * will not be
+ *
+ * @param type of class to be returned
+ * @param fqClassName fully-qualified class name
+ *
+ * @return newly loaded class instance, null if class could not be found
+ *
+ * @see #loadRequiredClass(String)
+ * @see #loadToolingSafeClass(String)
+ * @see ClassUtils#getDefaultClassLoader()
+ */
+ @SuppressWarnings("unchecked")
+ public static Class extends T> loadClass(String fqClassName) {
+ try {
+ return (Class extends T>) ClassUtils.getDefaultClassLoader().loadClass(fqClassName);
+ } catch (ClassNotFoundException ex) {
+ return null;
+ }
+ }
+
+ /**
+ * Loads the specified class using the default class loader, rethrowing any
+ * {@link ClassNotFoundException} as an unchecked exception.
+ *
+ * @param type of class to be returned
+ * @param fqClassName fully-qualified class name
+ *
+ * @return newly loaded class instance
+ *
+ * @throws IllegalArgumentException if configClassName cannot be loaded.
+ *
+ * @see #loadClass(String)
+ * @see #loadToolingSafeClass(String)
+ * @see ClassUtils#getDefaultClassLoader()
+ */
+ @SuppressWarnings("unchecked")
+ public static Class extends T> loadRequiredClass(String fqClassName) {
+ try {
+ return (Class extends T>) getDefaultClassLoader().loadClass(fqClassName);
+ } catch (ClassNotFoundException ex) {
+ throw new IllegalArgumentException(format(
+ "Class [%s] could not be loaded, check your CLASSPATH.", fqClassName), ex);
+ }
+ }
+
+ /**
+ * Loads the specified class using the default class loader, gracefully handling any
+ * {@link ClassNotFoundException} that may be thrown by issuing a WARN level logging
+ * statement and return null. This functionality is specifically implemented to
+ * accomodate tooling (Spring IDE) concerns, where user-defined types will not be
+ * available to the tooling.
+ *
+ * ASM class reading is used throughout JavaConfig, but there are certain cases where
+ * classloading cannot be avoided - specifically in cases where users define their own
+ * {@link Extension} or {@link Factory} annotations. This method should therefore be
+ * used sparingly but consistently where required.
+ *
+ * Because {@link ClassNotFoundException} is compensated for by returning null, callers
+ * must take care to handle the null case appropriately.
+ *
+ * In cases where the WARN logging statement is not desired, use the
+ * {@link #loadClass(String)} method, which returns null but issues no logging
+ * statements.
+ *
+ * This method should only ever return null in the case of a user-defined type be
+ * processed at tooling time. Therefore, tooling may not be able to represent any custom
+ * annotation semantics, but JavaConfig itself will not have any problem loading and
+ * respecting them at actual runtime.
+ *
+ * @param type of class to be returned
+ * @param fqClassName fully-qualified class name
+ *
+ * @return newly loaded class, null if class could not be found.
+ *
+ * @see #loadClass(String)
+ * @see #loadRequiredClass(String)
+ * @see ClassUtils#getDefaultClassLoader()
+ */
+ @SuppressWarnings("unchecked")
+ public static Class extends T> loadToolingSafeClass(String fqClassName) {
+ try {
+ return (Class extends T>) ClassUtils.getDefaultClassLoader().loadClass(fqClassName);
+ } catch (ClassNotFoundException ex) {
+ log.warn(format("Unable to load class [%s], likely due to tooling-specific restrictions."
+ + "Attempting to continue, but unexpected errors may occur", fqClassName), ex);
+ return null;
+ }
+ }
+
+ /**
+ * Uses the default ClassLoader to load pathToClass. Appends '.class' to
+ * pathToClass before attempting to load.
+ *
+ * @param pathToClass resource path to class, not including .class suffix. e.g.:
+ * com/acme/MyClass
+ *
+ * @return inputStream for pathToClass
+ *
+ * @throws RuntimeException if pathToClass does not exist
+ */
+ public static InputStream getClassAsStream(String pathToClass) {
+ String classFileName = pathToClass + ClassUtils.CLASS_FILE_SUFFIX;
+
+ InputStream is = ClassUtils.getDefaultClassLoader().getResourceAsStream(classFileName);
+
+ if (is == null)
+ throw new RuntimeException(new FileNotFoundException("Class file [" + classFileName
+ + "] not found"));
+
+ return is;
+ }
}
diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/Validatable.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/Validatable.java
index a5ce87e3187..a6546774f32 100644
--- a/org.springframework.config.java/src/main/java/org/springframework/config/java/Validatable.java
+++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/Validatable.java
@@ -2,18 +2,19 @@ package org.springframework.config.java;
import java.util.List;
+
/**
* Indicates a type is able to be validated for errors.
*
* @see Validator
- *
+ *
* @author Chris Beams
*/
public interface Validatable {
- /**
- * Validates this object, adding any errors to the supplied list of errors.
- */
- public void validate(List errors);
+ /**
+ * Validates this object, adding any errors to the supplied list of errors.
+ */
+ public void validate(List errors);
}
diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/Validator.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/Validator.java
index 7246ee0ee7d..09b577056d7 100644
--- a/org.springframework.config.java/src/main/java/org/springframework/config/java/Validator.java
+++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/Validator.java
@@ -4,10 +4,10 @@ import java.util.List;
/** Marker interface */
-//TODO: SJC-242 document
-//TODO: SJC-242 rename
+// TODO: SJC-242 document
+// TODO: SJC-242 rename
public interface Validator {
- boolean supports(Object object);
-
- void validate(Object object, List errors);
+ boolean supports(Object object);
+
+ void validate(Object object, List errors);
}
diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/ext/AbstractMethodInterceptor.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/ext/AbstractMethodInterceptor.java
index d03684a7481..698c5b85457 100644
--- a/org.springframework.config.java/src/main/java/org/springframework/config/java/ext/AbstractMethodInterceptor.java
+++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/ext/AbstractMethodInterceptor.java
@@ -30,19 +30,19 @@ import org.springframework.util.Assert;
/**
* Base class for all {@link MethodInterceptor} implementations.
- *
+ *
* @author Chris Beams
*/
public abstract class AbstractMethodInterceptor implements BeanFactoryAware, MethodInterceptor {
- protected final Log log = LogFactory.getLog(this.getClass());
- protected DefaultListableBeanFactory beanFactory;
+ protected final Log log = LogFactory.getLog(this.getClass());
+ protected DefaultListableBeanFactory beanFactory;
- public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
- Assert.isInstanceOf(DefaultListableBeanFactory.class, beanFactory);
- this.beanFactory = (DefaultListableBeanFactory) beanFactory;
- }
+ public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
+ Assert.isInstanceOf(DefaultListableBeanFactory.class, beanFactory);
+ this.beanFactory = (DefaultListableBeanFactory) beanFactory;
+ }
- protected String getBeanName(Method method) {
- return method.getName();
- }
+ protected String getBeanName(Method method) {
+ return method.getName();
+ }
}
diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/ext/Bean.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/ext/Bean.java
index 5c2e74ef3cb..a7eb53ac26b 100644
--- a/org.springframework.config.java/src/main/java/org/springframework/config/java/ext/Bean.java
+++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/ext/Bean.java
@@ -37,181 +37,184 @@ import org.springframework.config.java.Validator;
/**
- * Annotation to be applied to methods that create beans in a Spring context. The name of the bean
- * is the method name. (It is also possible to specify aliases using the aliases array on this
- * annotation.)
+ * Annotation to be applied to methods that create beans in a Spring context. The name of
+ * the bean is the method name. (It is also possible to specify aliases using the aliases
+ * array on this annotation.)
*
- *
Contains information similar to that held in Spring's internal BeanDefinition metadata.
+ *
+ * Contains information similar to that held in Spring's internal BeanDefinition metadata.
+ *
+ *
+ *
+ * Bean creation methods must be non-private (default, public or protected). Bean creation
+ * methods may throw any exception, which will be caught and handled by the Spring container
+ * on processing of the configuration class.
+ * Bean creation methods must return an object type. The decision to return a class or an
+ * interface will be significant in the event of proxying. Bean methods that return
+ * interfaces will be proxied using dynamic proxies; those that return a class will require
+ * CGLIB or other subclass-based proxying. It is recommended to return an interface where
+ * possible, as this is also consistent with best practice around loose coupling.
+ *
+ *
+ *
+ * Bean creation methods may reference other bean creation methods by calling them directly,
+ * as follows. This ensures that references between beans are strongly typed:
+ *
*
- *
Bean creation methods must be non-private (default, public or protected). Bean creation
- * methods may throw any exception, which will be caught and handled by the Spring container on
- * processing of the configuration class.
- * Bean creation methods must return an object type. The decision to return a class or an interface
- * will be significant in the event of proxying. Bean methods that return interfaces will be proxied
- * using dynamic proxies; those that return a class will require CGLIB or other subclass-based
- * proxying. It is recommended to return an interface where possible, as this is also consistent
- * with best practice around loose coupling.
- *
- *
Bean creation methods may reference other bean creation methods by calling them directly, as
- * follows. This ensures that references between beans are strongly typed:
- *
* @see Configuration
* @see BeanNamingStrategy
- *
- * @author Rod Johnson
- * @author Costin Leau
- * @author Chris Beams
+ *
+ * @author Rod Johnson
+ * @author Costin Leau
+ * @author Chris Beams
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
-@Factory(registrarType=BeanRegistrar.class,
- callbackType=BeanMethodInterceptor.class,
- validatorTypes={BeanValidator.class, IllegalBeanOverrideValidator.class})
+@Factory(registrarType = BeanRegistrar.class, callbackType = BeanMethodInterceptor.class, validatorTypes = {
+ BeanValidator.class, IllegalBeanOverrideValidator.class })
public @interface Bean {
- /**
- * Role this bean plays in the overall application configuration.
- *
- * @see BeanDefinition#ROLE_APPLICATION
- * @see BeanDefinition#ROLE_INFRASTRUCTURE
- * @see BeanDefinition#ROLE_SUPPORT
- *
- * @see AbstractBeanDefinition the 'role' field is assigned by default to ROLE_APPLICATION
- */
- int role() default BeanDefinition.ROLE_APPLICATION;
-
- /**
- * Bean aliases.
- */
- String[] aliases() default { };
-
- /**
- * Scope: whether the bean is a singleton, prototype or custom scope.
- * Default is singleton.
- */
- String scope() default Scopes.SINGLETON;
-
- /**
- * Bean autowire strategy.
- */
- Autowire autowire() default Autowire.INHERITED;
-
-// /**
-// * Bean lazy strategy.
-// */
-// Lazy lazy() default Lazy.UNSPECIFIED;
-//
-// /**
-// * A bean may be marked as primary, useful for disambiguation when looking
-// * up beans by type.
-// *
-// * @see org.springframework.config.java.context.JavaConfigApplicationContext#getBean(Class);
-// */
-// Primary primary() default Primary.UNSPECIFIED;
-
- /**
- * Bean init method name. Normally this is not needed, as the initialization
- * (with parameterization) can be done directly through java code.
- */
- String initMethodName() default "";
-
- /**
- * Bean destroy method name.
- */
- String destroyMethodName() default "";
-
-// /**
-// * Bean dependency check strategy.
-// */
-// DependencyCheck dependencyCheck() default DependencyCheck.UNSPECIFIED;
-
- /**
- * Beans on which the current bean depends on.
- */
- String[] dependsOn() default { };
-
-// /**
-// * Metadata for the current bean.
-// */
-// Meta[] meta() default { };
-
- /**
- * Allow the bean to be overridden in another JavaConfig, XML or other
- * non-Java configuration. This is consistent with
- * DefaultListableBeanFactory's allowBeanDefinitionOverriding property,
- * which defaults to true.
- *
- * @return whether overriding of this bean is allowed
- */
- boolean allowOverriding() default true;
+ /**
+ * Role this bean plays in the overall application configuration.
+ *
+ * @see BeanDefinition#ROLE_APPLICATION
+ * @see BeanDefinition#ROLE_INFRASTRUCTURE
+ * @see BeanDefinition#ROLE_SUPPORT
+ *
+ * @see AbstractBeanDefinition the 'role' field is assigned by default to
+ * ROLE_APPLICATION
+ */
+ int role() default BeanDefinition.ROLE_APPLICATION;
+
+ /**
+ * Bean aliases.
+ */
+ String[] aliases() default {};
+
+ /**
+ * Scope: whether the bean is a singleton, prototype or custom scope. Default is
+ * singleton.
+ */
+ String scope() default Scopes.SINGLETON;
+
+ /**
+ * Bean autowire strategy.
+ */
+ Autowire autowire() default Autowire.INHERITED;
+
+ // /**
+ // * Bean lazy strategy.
+ // */
+ // Lazy lazy() default Lazy.UNSPECIFIED;
+ //
+ // /**
+ // * A bean may be marked as primary, useful for disambiguation when looking
+ // * up beans by type.
+ // *
+ // * @see
+ // org.springframework.config.java.context.JavaConfigApplicationContext#getBean(Class);
+ // */
+ // Primary primary() default Primary.UNSPECIFIED;
+
+ /**
+ * Bean init method name. Normally this is not needed, as the initialization (with
+ * parameterization) can be done directly through java code.
+ */
+ String initMethodName() default "";
+
+ /**
+ * Bean destroy method name.
+ */
+ String destroyMethodName() default "";
+
+ // /**
+ // * Bean dependency check strategy.
+ // */
+ // DependencyCheck dependencyCheck() default DependencyCheck.UNSPECIFIED;
+
+ /**
+ * Beans on which the current bean depends on.
+ */
+ String[] dependsOn() default {};
+
+ // /**
+ // * Metadata for the current bean.
+ // */
+ // Meta[] meta() default { };
+
+ /**
+ * Allow the bean to be overridden in another JavaConfig, XML or other non-Java
+ * configuration. This is consistent with DefaultListableBeanFactory's
+ * allowBeanDefinitionOverriding property, which defaults to true.
+ *
+ * @return whether overriding of this bean is allowed
+ */
+ boolean allowOverriding() default true;
}
/**
* Detects any user errors when declaring {@link Bean}-annotated methods.
- *
+ *
* @author Chris Beams
*/
class BeanValidator implements Validator {
- public boolean supports(Object object) {
- return object instanceof ModelMethod;
- }
-
- public void validate(Object object, List errors) {
- ModelMethod method = (ModelMethod) object;
-
- // TODO: re-enable for @ScopedProxy support
-// if (method.getAnnotation(ScopedProxy.class) == null)
-// return;
-//
-// Bean bean = method.getRequiredAnnotation(Bean.class);
-//
-// if (bean.scope().equals(DefaultScopes.SINGLETON)
-// || bean.scope().equals(DefaultScopes.PROTOTYPE))
-// errors.add(new InvalidScopedProxyDeclarationError(method));
- }
-
+ public boolean supports(Object object) {
+ return object instanceof ModelMethod;
+ }
+
+ public void validate(Object object, List errors) {
+ ModelMethod method = (ModelMethod) object;
+
+ // TODO: re-enable for @ScopedProxy support
+ // if (method.getAnnotation(ScopedProxy.class) == null)
+ // return;
+ //
+ // Bean bean = method.getRequiredAnnotation(Bean.class);
+ //
+ // if (bean.scope().equals(DefaultScopes.SINGLETON)
+ // || bean.scope().equals(DefaultScopes.PROTOTYPE))
+ // errors.add(new InvalidScopedProxyDeclarationError(method));
+ }
+
}
-
+
/**
* Detects any illegally-overridden {@link Bean} definitions within a particular
* {@link ConfigurationModel}
*
* @see Bean#allowOverriding()
- *
+ *
* @author Chris Beams
*/
class IllegalBeanOverrideValidator implements Validator {
-
- public boolean supports(Object object) {
- return object instanceof ConfigurationModel;
- }
-
- public void validate(Object object, List errors) {
- ConfigurationModel model = (ConfigurationModel) object;
-
- ConfigurationClass[] allClasses = model.getAllConfigurationClasses();
-
- for (int i = 0; i < allClasses.length; i++) {
- for (ModelMethod method : allClasses[i].getMethods()) {
- Bean bean = method.getAnnotation(Bean.class);
-
- if (bean == null || bean.allowOverriding())
- continue;
-
- for (int j = i + 1; j < allClasses.length; j++)
- if (allClasses[j].hasMethod(method.getName()))
- errors.add(allClasses[i].new IllegalBeanOverrideError(allClasses[j], method));
- }
- }
- }
+
+ public boolean supports(Object object) {
+ return object instanceof ConfigurationModel;
+ }
+
+ public void validate(Object object, List errors) {
+ ConfigurationModel model = (ConfigurationModel) object;
+
+ ConfigurationClass[] allClasses = model.getAllConfigurationClasses();
+
+ for (int i = 0; i < allClasses.length; i++) {
+ for (ModelMethod method : allClasses[i].getMethods()) {
+ Bean bean = method.getAnnotation(Bean.class);
+
+ if (bean == null || bean.allowOverriding())
+ continue;
+
+ for (int j = i + 1; j < allClasses.length; j++)
+ if (allClasses[j].hasMethod(method.getName()))
+ errors.add(allClasses[i].new IllegalBeanOverrideError(allClasses[j], method));
+ }
+ }
+ }
}
-
-
-
diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/ext/BeanMethodInterceptor.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/ext/BeanMethodInterceptor.java
index 8904e14ac70..996dc4e9b41 100644
--- a/org.springframework.config.java/src/main/java/org/springframework/config/java/ext/BeanMethodInterceptor.java
+++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/ext/BeanMethodInterceptor.java
@@ -23,6 +23,7 @@ import net.sf.cglib.proxy.MethodProxy;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+
/**
* Intercepts the invocation of any {@link Bean}-annotated methods in order to ensure proper
* handling of bean semantics such as scoping and AOP proxying.
@@ -34,51 +35,54 @@ import org.springframework.beans.factory.config.ConfigurableBeanFactory;
*/
class BeanMethodInterceptor extends AbstractMethodInterceptor {
- /**
- * Enhances a {@link Bean @Bean} method to check the supplied BeanFactory for the existence
- * of this bean object.
- */
- public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
- String beanName = getBeanName(method);
-
- // TODO: re-enable for @ScopedProxy support
-// boolean isScopedProxy = (AnnotationUtils.findAnnotation(method, ScopedProxy.class) != null);
-//
-// String scopedBeanName = ScopedProxy.Util.resolveHiddenScopedProxyBeanName(beanName);
-// if (isScopedProxy && beanFactory.isCurrentlyInCreation(scopedBeanName))
-// beanName = scopedBeanName;
+ /**
+ * Enhances a {@link Bean @Bean} method to check the supplied BeanFactory for the
+ * existence of this bean object.
+ */
+ public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
+ String beanName = getBeanName(method);
+
+ // TODO: re-enable for @ScopedProxy support
+ // boolean isScopedProxy = (AnnotationUtils.findAnnotation(method,
+ // ScopedProxy.class) != null);
+ //
+ // String scopedBeanName =
+ // ScopedProxy.Util.resolveHiddenScopedProxyBeanName(beanName);
+ // if (isScopedProxy && beanFactory.isCurrentlyInCreation(scopedBeanName))
+ // beanName = scopedBeanName;
- if (factoryContainsBean(beanName)) {
- // we have an already existing cached instance of this bean -> retrieve it
- Object cachedBean = beanFactory.getBean(beanName);
- if (log.isInfoEnabled())
- log.info(format("Returning cached singleton object [%s] for @Bean method %s.%s",
- cachedBean, method.getDeclaringClass().getSimpleName(), beanName));
+ if (factoryContainsBean(beanName)) {
+ // we have an already existing cached instance of this bean -> retrieve it
+ Object cachedBean = beanFactory.getBean(beanName);
+ if (log.isInfoEnabled())
+ log.info(format("Returning cached singleton object [%s] for @Bean method %s.%s", cachedBean,
+ method.getDeclaringClass().getSimpleName(), beanName));
- return cachedBean;
- }
+ return cachedBean;
+ }
- return proxy.invokeSuper(obj, args);
- }
+ return proxy.invokeSuper(obj, args);
+ }
- /**
- * Check the beanFactory to see whether the bean named beanName already exists.
- * Accounts for the fact that the requested bean may be "in creation", i.e.: we're in the
- * middle of servicing the initial request for this bean. From JavaConfig's perspective,
- * this means that the bean does not actually yet exist, and that it is now our job to
- * create it for the first time by executing the logic in the corresponding Bean method.
- *
- * Said another way, this check repurposes {@link ConfigurableBeanFactory#isCurrentlyInCreation(String)}
- * to determine whether the container is calling this method or the user is calling this method.
- *
- * @param beanName name of bean to check for
- *
- * @return true if beanName already exists in beanFactory
- */
- private boolean factoryContainsBean(String beanName) {
- return beanFactory.containsBean(beanName)
- && !beanFactory.isCurrentlyInCreation(beanName);
- }
+ /**
+ * Check the beanFactory to see whether the bean named beanName already
+ * exists. Accounts for the fact that the requested bean may be "in creation", i.e.:
+ * we're in the middle of servicing the initial request for this bean. From JavaConfig's
+ * perspective, this means that the bean does not actually yet exist, and that it is now
+ * our job to create it for the first time by executing the logic in the corresponding
+ * Bean method.
+ *
+ * Said another way, this check repurposes
+ * {@link ConfigurableBeanFactory#isCurrentlyInCreation(String)} to determine whether
+ * the container is calling this method or the user is calling this method.
+ *
+ * @param beanName name of bean to check for
+ *
+ * @return true if beanName already exists in beanFactory
+ */
+ private boolean factoryContainsBean(String beanName) {
+ return beanFactory.containsBean(beanName) && !beanFactory.isCurrentlyInCreation(beanName);
+ }
}
diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/ext/BeanRegistrar.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/ext/BeanRegistrar.java
index b62eca4a9fb..5151b1c19f3 100644
--- a/org.springframework.config.java/src/main/java/org/springframework/config/java/ext/BeanRegistrar.java
+++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/ext/BeanRegistrar.java
@@ -26,178 +26,183 @@ import org.springframework.util.Assert;
// TODO: SJC-242 document BeanHandler
// TODO: SJC-242 make package-private
class BeanRegistrar implements BeanDefinitionRegistrar {
-
- private static final Log logger = LogFactory.getLog(BeanRegistrar.class);
-
- /**
- * Ensures that member is a method and is annotated (directly or indirectly)
- * with {@link Bean @Bean}.
- */
- public boolean accepts(Method method) {
- return AnnotationUtils.findAnnotation(method, Bean.class) != null;
- }
-
- // TODO: SJC-242 method too long
- public void register(ModelMethod method, BeanDefinitionRegistry registry) {
- RootBeanDefinition beanDef = new JavaConfigBeanDefinition();
-
- ConfigurationClass configClass = method.getDeclaringClass();
-
- beanDef.setFactoryBeanName(configClass.getBeanName());
- beanDef.setFactoryMethodName(method.getName());
-
- Bean bean = method.getRequiredAnnotation(Bean.class);
-
- Configuration defaults = configClass.getMetadata();
-
- // consider scoping
- beanDef.setScope(bean.scope());
-
- // consider autowiring
- if (bean.autowire() != AnnotationUtils.getDefaultValue(Bean.class, "autowire"))
- beanDef.setAutowireMode(bean.autowire().value());
- else if (defaults.defaultAutowire() != AnnotationUtils.getDefaultValue(Configuration.class, "defaultAutowire"))
- beanDef.setAutowireMode(defaults.defaultAutowire().value());
-
- String beanName = method.getName();
-
- // has this already been overriden (i.e.: via XML)?
- if (containsBeanDefinitionIncludingAncestry(beanName, registry)) {
- BeanDefinition existingBeanDef = getBeanDefinitionIncludingAncestry(beanName, registry);
-
- // is the existing bean definition one that was created by JavaConfig?
- if (!(existingBeanDef instanceof JavaConfigBeanDefinition)) {
- // no -> then it's an external override, probably XML
-
- // ensure that overriding is ok
- if (bean.allowOverriding() == false) {
- UsageError error = configClass.new IllegalBeanOverrideError(null, method);
- throw new MalformedConfigurationException(error);
- }
-
- // overriding is legal, return immediately
- logger.info(format("Skipping loading bean definition for %s: a definition for bean '%s' already exists. "
- + "This is likely due to an override in XML.",
- method, beanName));
- return;
- }
- }
-
- // propagate this bean's 'role' attribute
- beanDef.setRole(bean.role());
-
- // consider aliases
- for (String alias : bean.aliases())
- registry.registerAlias(beanName, alias);
-
- // TODO: re-enable for Lazy support
-// // is this bean marked as primary for disambiguation?
-// if (bean.primary() == Primary.TRUE)
-// beanDef.setPrimary(true);
-//
-// // is this bean lazily instantiated?
-// if ((bean.lazy() == Lazy.TRUE)
-// || ((bean.lazy() == Lazy.UNSPECIFIED) && (defaults.defaultLazy() == Lazy.TRUE)))
-// beanDef.setLazyInit(true);
-
- // does this bean have a custom init-method specified?
- String initMethodName = bean.initMethodName();
- if (hasText(initMethodName))
- beanDef.setInitMethodName(initMethodName);
-
- // does this bean have a custom destroy-method specified?
- String destroyMethodName = bean.destroyMethodName();
- if (hasText(destroyMethodName))
- beanDef.setDestroyMethodName(destroyMethodName);
-
- // TODO: re-enable for @ScopedProxy support
- // is this method annotated with @ScopedProxy?
-// ScopedProxy scopedProxy = method.getAnnotation(ScopedProxy.class);
-// if (scopedProxy != null) {
-// RootBeanDefinition targetDef = beanDef;
-//
-// // Create a scoped proxy definition for the original bean name,
-// // "hiding" the target bean in an internal target definition.
-// String targetBeanName = ScopedProxy.Util.resolveHiddenScopedProxyBeanName(beanName);
-// RootBeanDefinition scopedProxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class);
-// scopedProxyDefinition.getPropertyValues().addPropertyValue("targetBeanName", targetBeanName);
-//
-// if (scopedProxy.proxyTargetClass())
-// targetDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
-// // ScopedFactoryBean's "proxyTargetClass" default is TRUE, so we
-// // don't need to set it explicitly here.
-// else
-// scopedProxyDefinition.getPropertyValues().addPropertyValue("proxyTargetClass", Boolean.FALSE);
-//
-// // The target bean should be ignored in favor of the scoped proxy.
-// targetDef.setAutowireCandidate(false);
-//
-// // Register the target bean as separate bean in the factory
-// registry.registerBeanDefinition(targetBeanName, targetDef);
-//
-// // replace the original bean definition with the target one
-// beanDef = scopedProxyDefinition;
-// }
-
- // TODO: re-enable for @Meta support
- // does this bean method have any @Meta annotations?
-// for (Meta meta : bean.meta())
-// beanDef.addMetadataAttribute(new BeanMetadataAttribute(meta.key(), meta.value()));
-
- if(bean.dependsOn().length > 0)
- beanDef.setDependsOn(bean.dependsOn());
-
- logger.info(format("Registering bean definition for @Bean method %s.%s()",
- configClass.getName(), beanName));
-
- registry.registerBeanDefinition(beanName, beanDef);
-
- }
-
- private boolean containsBeanDefinitionIncludingAncestry(String beanName, BeanDefinitionRegistry registry) {
- try {
- getBeanDefinitionIncludingAncestry(beanName, registry);
- return true;
- } catch (NoSuchBeanDefinitionException ex) {
- return false;
- }
- }
-
- private BeanDefinition getBeanDefinitionIncludingAncestry(String beanName, BeanDefinitionRegistry registry) {
- Assert.isInstanceOf(ConfigurableListableBeanFactory.class, registry);
- ConfigurableListableBeanFactory clbf = (ConfigurableListableBeanFactory)registry;
-
- do {
- if (clbf.containsBeanDefinition(beanName))
- return registry.getBeanDefinition(beanName);
-
- BeanFactory parent = clbf.getParentBeanFactory();
- if (parent == null) {
- clbf = null;
- } else if (parent instanceof ConfigurableListableBeanFactory) {
- clbf = (ConfigurableListableBeanFactory) parent;
- // TODO: re-enable
-// } else if (parent instanceof AbstractApplicationContext) {
-// clbf = ((AbstractApplicationContext) parent).getBeanFactory();
- } else {
- throw new IllegalStateException("unknown parent type: " + parent.getClass().getName());
- }
- } while (clbf != null);
-
- throw new NoSuchBeanDefinitionException(
- format("No bean definition matching name '%s' "
- + "could be found in %s or its ancestry", beanName, registry));
- }
+
+ private static final Log logger = LogFactory.getLog(BeanRegistrar.class);
+
+ /**
+ * Ensures that member is a method and is annotated (directly or indirectly)
+ * with {@link Bean @Bean}.
+ */
+ public boolean accepts(Method method) {
+ return AnnotationUtils.findAnnotation(method, Bean.class) != null;
+ }
+
+ // TODO: SJC-242 method too long
+ public void register(ModelMethod method, BeanDefinitionRegistry registry) {
+ RootBeanDefinition beanDef = new ConfigurationClassBeanDefinition();
+
+ ConfigurationClass configClass = method.getDeclaringClass();
+
+ beanDef.setFactoryBeanName(configClass.getBeanName());
+ beanDef.setFactoryMethodName(method.getName());
+
+ Bean bean = method.getRequiredAnnotation(Bean.class);
+
+ Configuration defaults = configClass.getMetadata();
+
+ // consider scoping
+ beanDef.setScope(bean.scope());
+
+ // consider autowiring
+ if (bean.autowire() != AnnotationUtils.getDefaultValue(Bean.class, "autowire"))
+ beanDef.setAutowireMode(bean.autowire().value());
+ else if (defaults.defaultAutowire() != AnnotationUtils.getDefaultValue(Configuration.class,
+ "defaultAutowire"))
+ beanDef.setAutowireMode(defaults.defaultAutowire().value());
+
+ String beanName = method.getName();
+
+ // has this already been overriden (i.e.: via XML)?
+ if (containsBeanDefinitionIncludingAncestry(beanName, registry)) {
+ BeanDefinition existingBeanDef = getBeanDefinitionIncludingAncestry(beanName, registry);
+
+ // is the existing bean definition one that was created by JavaConfig?
+ if (!(existingBeanDef instanceof ConfigurationClassBeanDefinition)) {
+ // no -> then it's an external override, probably XML
+
+ // ensure that overriding is ok
+ if (bean.allowOverriding() == false) {
+ UsageError error = configClass.new IllegalBeanOverrideError(null, method);
+ throw new MalformedConfigurationException(error);
+ }
+
+ // overriding is legal, return immediately
+ logger.info(format(
+ "Skipping loading bean definition for %s: a definition for bean '%s' already exists. "
+ + "This is likely due to an override in XML.", method, beanName));
+ return;
+ }
+ }
+
+ // propagate this bean's 'role' attribute
+ beanDef.setRole(bean.role());
+
+ // consider aliases
+ for (String alias : bean.aliases())
+ registry.registerAlias(beanName, alias);
+
+ // TODO: re-enable for Lazy support
+ // // is this bean marked as primary for disambiguation?
+ // if (bean.primary() == Primary.TRUE)
+ // beanDef.setPrimary(true);
+ //
+ // // is this bean lazily instantiated?
+ // if ((bean.lazy() == Lazy.TRUE)
+ // || ((bean.lazy() == Lazy.UNSPECIFIED) && (defaults.defaultLazy() == Lazy.TRUE)))
+ // beanDef.setLazyInit(true);
+
+ // does this bean have a custom init-method specified?
+ String initMethodName = bean.initMethodName();
+ if (hasText(initMethodName))
+ beanDef.setInitMethodName(initMethodName);
+
+ // does this bean have a custom destroy-method specified?
+ String destroyMethodName = bean.destroyMethodName();
+ if (hasText(destroyMethodName))
+ beanDef.setDestroyMethodName(destroyMethodName);
+
+ // TODO: re-enable for @ScopedProxy support
+ // is this method annotated with @ScopedProxy?
+ // ScopedProxy scopedProxy = method.getAnnotation(ScopedProxy.class);
+ // if (scopedProxy != null) {
+ // RootBeanDefinition targetDef = beanDef;
+ //
+ // // Create a scoped proxy definition for the original bean name,
+ // // "hiding" the target bean in an internal target definition.
+ // String targetBeanName =
+ // ScopedProxy.Util.resolveHiddenScopedProxyBeanName(beanName);
+ // RootBeanDefinition scopedProxyDefinition = new
+ // RootBeanDefinition(ScopedProxyFactoryBean.class);
+ // scopedProxyDefinition.getPropertyValues().addPropertyValue("targetBeanName",
+ // targetBeanName);
+ //
+ // if (scopedProxy.proxyTargetClass())
+ // targetDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE,
+ // Boolean.TRUE);
+ // // ScopedFactoryBean's "proxyTargetClass" default is TRUE, so we
+ // // don't need to set it explicitly here.
+ // else
+ // scopedProxyDefinition.getPropertyValues().addPropertyValue("proxyTargetClass",
+ // Boolean.FALSE);
+ //
+ // // The target bean should be ignored in favor of the scoped proxy.
+ // targetDef.setAutowireCandidate(false);
+ //
+ // // Register the target bean as separate bean in the factory
+ // registry.registerBeanDefinition(targetBeanName, targetDef);
+ //
+ // // replace the original bean definition with the target one
+ // beanDef = scopedProxyDefinition;
+ // }
+
+ // TODO: re-enable for @Meta support
+ // does this bean method have any @Meta annotations?
+ // for (Meta meta : bean.meta())
+ // beanDef.addMetadataAttribute(new BeanMetadataAttribute(meta.key(),
+ // meta.value()));
+
+ if (bean.dependsOn().length > 0)
+ beanDef.setDependsOn(bean.dependsOn());
+
+ logger.info(format("Registering bean definition for @Bean method %s.%s()", configClass.getName(),
+ beanName));
+
+ registry.registerBeanDefinition(beanName, beanDef);
+
+ }
+
+ private boolean containsBeanDefinitionIncludingAncestry(String beanName, BeanDefinitionRegistry registry) {
+ try {
+ getBeanDefinitionIncludingAncestry(beanName, registry);
+ return true;
+ } catch (NoSuchBeanDefinitionException ex) {
+ return false;
+ }
+ }
+
+ private BeanDefinition getBeanDefinitionIncludingAncestry(String beanName, BeanDefinitionRegistry registry) {
+ Assert.isInstanceOf(ConfigurableListableBeanFactory.class, registry);
+ ConfigurableListableBeanFactory clbf = (ConfigurableListableBeanFactory) registry;
+
+ do {
+ if (clbf.containsBeanDefinition(beanName))
+ return registry.getBeanDefinition(beanName);
+
+ BeanFactory parent = clbf.getParentBeanFactory();
+ if (parent == null) {
+ clbf = null;
+ } else if (parent instanceof ConfigurableListableBeanFactory) {
+ clbf = (ConfigurableListableBeanFactory) parent;
+ // TODO: re-enable
+ // } else if (parent instanceof AbstractApplicationContext) {
+ // clbf = ((AbstractApplicationContext) parent).getBeanFactory();
+ } else {
+ throw new IllegalStateException("unknown parent type: " + parent.getClass().getName());
+ }
+ } while (clbf != null);
+
+ throw new NoSuchBeanDefinitionException(format("No bean definition matching name '%s' "
+ + "could be found in %s or its ancestry", beanName, registry));
+ }
}
/**
- * {@link RootBeanDefinition} marker subclass used to signify that a bean definition
- * created by JavaConfig as opposed to any other configuration source. Used in bean
- * overriding cases where it's necessary to determine whether the bean definition was created
- * externally (e.g. via XML).
+ * {@link RootBeanDefinition} marker subclass used to signify that a bean definition created
+ * by JavaConfig as opposed to any other configuration source. Used in bean overriding cases
+ * where it's necessary to determine whether the bean definition was created externally
+ * (e.g. via XML).
*/
@SuppressWarnings("serial")
-// TODO: SJC-242 what to do about JavaConfigBeanDefinition?
-class JavaConfigBeanDefinition extends RootBeanDefinition {
+class ConfigurationClassBeanDefinition extends RootBeanDefinition {
}
\ No newline at end of file
diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/internal/enhancement/AddAnnotationAdapter.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/internal/enhancement/AddAnnotationAdapter.java
index 688ae7333d7..bbd8834b6f7 100644
--- a/org.springframework.config.java/src/main/java/org/springframework/config/java/internal/enhancement/AddAnnotationAdapter.java
+++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/internal/enhancement/AddAnnotationAdapter.java
@@ -24,93 +24,92 @@ import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
-
/**
- * Transforms a class by adding bytecode for a class-level annotation.
- * Checks to ensure that the desired annotation is not already present
- * before adding. Used by {@link ConfigurationEnhancer} to dynamically add
- * an {@link org.aspectj.lang.Aspect} annotation to an enhanced Configuration
- * subclass.
+ * Transforms a class by adding bytecode for a class-level annotation. Checks to ensure that
+ * the desired annotation is not already present before adding. Used by
+ * {@link ConfigurationEnhancer} to dynamically add an {@link org.aspectj.lang.Aspect}
+ * annotation to an enhanced Configuration subclass.
*
* This class was originally adapted from examples the ASM 3.0 documentation.
- *
+ *
* @author Chris Beams
*/
class AddAnnotationAdapter extends ClassAdapter {
- private String annotationDesc;
- private boolean isAnnotationPresent;
+ private String annotationDesc;
+ private boolean isAnnotationPresent;
- /**
- * Creates a new AddAnnotationAdapter instance.
- *
- * @param cv the ClassVisitor delegate
- * @param annotationDesc name of the annotation to be added
- * (in type descriptor format)
- */
- public AddAnnotationAdapter(ClassVisitor cv, String annotationDesc) {
- super(cv);
- this.annotationDesc = annotationDesc;
- }
+ /**
+ * Creates a new AddAnnotationAdapter instance.
+ *
+ * @param cv the ClassVisitor delegate
+ * @param annotationDesc name of the annotation to be added (in type descriptor format)
+ */
+ public AddAnnotationAdapter(ClassVisitor cv, String annotationDesc) {
+ super(cv);
+ this.annotationDesc = annotationDesc;
+ }
- /**
- * Ensures that the version of the resulting class is Java 5 or better.
- */
- @Override
- public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
- int v = (version & 0xFF) < Constants.V1_5 ? Constants.V1_5 : version;
- cv.visit(v, access, name, signature, superName, interfaces);
- }
+ /**
+ * Ensures that the version of the resulting class is Java 5 or better.
+ */
+ @Override
+ public void visit(int version, int access, String name, String signature, String superName,
+ String[] interfaces) {
+ int v = (version & 0xFF) < Constants.V1_5 ? Constants.V1_5 : version;
+ cv.visit(v, access, name, signature, superName, interfaces);
+ }
- /**
- * Checks to ensure that the desired annotation is not already present.
- */
- @Override
- public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
- if (visible && desc.equals(annotationDesc)) {
- isAnnotationPresent = true;
- }
- return cv.visitAnnotation(desc, visible);
- }
+ /**
+ * Checks to ensure that the desired annotation is not already present.
+ */
+ @Override
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ if (visible && desc.equals(annotationDesc)) {
+ isAnnotationPresent = true;
+ }
+ return cv.visitAnnotation(desc, visible);
+ }
- @Override
- public void visitInnerClass(String name, String outerName, String innerName, int access) {
- addAnnotation();
- cv.visitInnerClass(name, outerName, innerName, access);
- }
+ @Override
+ public void visitInnerClass(String name, String outerName, String innerName, int access) {
+ addAnnotation();
+ cv.visitInnerClass(name, outerName, innerName, access);
+ }
- @Override
- public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
- addAnnotation();
- return cv.visitField(access, name, desc, signature, value);
- }
+ @Override
+ public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
+ addAnnotation();
+ return cv.visitField(access, name, desc, signature, value);
+ }
- @Override
- public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
- addAnnotation();
- return cv.visitMethod(access, name, desc, signature, exceptions);
- }
+ @Override
+ public MethodVisitor visitMethod(int access, String name, String desc, String signature,
+ String[] exceptions) {
+ addAnnotation();
+ return cv.visitMethod(access, name, desc, signature, exceptions);
+ }
- /**
- * Kicks off the process of actually adding the desired annotation.
- *
- * @see #addAnnotation()
- */
- @Override
- public void visitEnd() {
- addAnnotation();
- cv.visitEnd();
- }
+ /**
+ * Kicks off the process of actually adding the desired annotation.
+ *
+ * @see #addAnnotation()
+ */
+ @Override
+ public void visitEnd() {
+ addAnnotation();
+ cv.visitEnd();
+ }
- /**
- * Actually adds the desired annotation.
- */
- private void addAnnotation() {
- if (!isAnnotationPresent) {
- AnnotationVisitor av = cv.visitAnnotation(annotationDesc, true);
- if (av != null) {
- av.visitEnd();
- }
- isAnnotationPresent = true;
- }
- }
+ /**
+ * Actually adds the desired annotation.
+ */
+ private void addAnnotation() {
+ if (!isAnnotationPresent) {
+ AnnotationVisitor av = cv.visitAnnotation(annotationDesc, true);
+ if (av != null) {
+ av.visitEnd();
+ }
+ isAnnotationPresent = true;
+ }
+ }
}
diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/internal/enhancement/ConfigurationEnhancer.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/internal/enhancement/ConfigurationEnhancer.java
index 7838d6cb49a..399035aa3d3 100644
--- a/org.springframework.config.java/src/main/java/org/springframework/config/java/internal/enhancement/ConfigurationEnhancer.java
+++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/internal/enhancement/ConfigurationEnhancer.java
@@ -46,7 +46,6 @@ import org.springframework.config.java.ConfigurationModel;
import org.springframework.config.java.ModelMethod;
-
/**
* Enhances {@link Configuration} classes by generating a CGLIB subclass capable of
* interacting with the Spring container to respect bean semantics.
@@ -57,176 +56,173 @@ import org.springframework.config.java.ModelMethod;
*/
public class ConfigurationEnhancer {
- private static final Log log = LogFactory.getLog(ConfigurationEnhancer.class);
-
- private final ArrayList> callbackTypes =
- new ArrayList>();
-
- private final LinkedHashSet registrars =
- new LinkedHashSet();
-
- private final ArrayList callbackInstances =
- new ArrayList();
-
- private final CallbackFilter callbackFilter =
- new CallbackFilter() {
- public int accept(Method candidateMethod) {
- Iterator iter = registrars.iterator();
- for(int i=0; iter.hasNext(); i++)
- if(iter.next().accepts(candidateMethod))
- return i;
-
- throw new IllegalStateException(format("No registrar is capable of " +
- "handling method [%s]. Perhaps you forgot to add a catch-all registrar?",
- candidateMethod.getName()));
- }
- };
-
-
- /**
- * Creates a new {@link ConfigurationEnhancer} instance.
- */
- public ConfigurationEnhancer(DefaultListableBeanFactory beanFactory, ConfigurationModel model) {
- notNull(beanFactory, "beanFactory must be non-null");
- notNull(model, "model must be non-null");
-
- populateRegistrarsAndCallbacks(beanFactory, model);
- }
-
-
- /**
- * Reads the contents of {@code model} in order to populate {@link #registrars},
- * {@link #callbackInstances} and {@link #callbackTypes} appropriately.
- *
- * @see #callbackFilter
- */
- private void populateRegistrarsAndCallbacks(DefaultListableBeanFactory beanFactory, ConfigurationModel model) {
-
- for (ConfigurationClass configClass : model.getAllConfigurationClasses()) {
- for (ModelMethod method : configClass.getMethods()) {
- registrars.add(method.getRegistrar());
-
- Callback callback = method.getCallback();
-
- if(callback instanceof BeanFactoryAware)
- ((BeanFactoryAware)callback).setBeanFactory(beanFactory);
-
- callbackInstances.add(callback);
- }
- }
-
- // register a 'catch-all' registrar
- registrars.add(new BeanDefinitionRegistrar() {
-
- public boolean accepts(Method method) {
- return true;
- }
-
- public void register(ModelMethod method, BeanDefinitionRegistry registry) {
- // no-op
- }
- });
- callbackInstances.add(NoOp.INSTANCE);
-
- for(Callback callback : callbackInstances)
- callbackTypes.add(callback.getClass());
- }
-
-
- /**
- * Loads the specified class and generates a CGLIB subclass of it equipped with container-aware
- * callbacks capable of respecting scoping and other bean semantics.
- *
- * @return fully-qualified name of the enhanced subclass
- */
- public String enhance(String configClassName) {
- if (log.isInfoEnabled())
- log.info("Enhancing " + configClassName);
-
- Class> superclass = loadRequiredClass(configClassName);
-
- Class> subclass = createClass(newEnhancer(superclass), superclass);
-
- subclass = nestOneClassDeeperIfAspect(superclass, subclass);
-
- if (log.isInfoEnabled())
- log.info(format("Successfully enhanced %s; enhanced class name is: %s",
- configClassName, subclass.getName()));
-
- return subclass.getName();
- }
-
- /**
- * Creates a new CGLIB {@link Enhancer} instance.
- */
- private Enhancer newEnhancer(Class> superclass) {
- Enhancer enhancer = new Enhancer();
-
- // because callbackFilter and callbackTypes are dynamically populated
- // there's no opportunity for caching. This does not appear to be causing
- // any performance problem.
- enhancer.setUseCache(false);
-
- enhancer.setSuperclass(superclass);
- enhancer.setUseFactory(false);
- enhancer.setCallbackFilter(callbackFilter);
- enhancer.setCallbackTypes(callbackTypes.toArray(new Class>[]{}));
-
- return enhancer;
- }
-
- /**
- * Uses enhancer to generate a subclass of superclass, ensuring that
- * {@link #callbackInstances} are registered for the new subclass.
- */
- private Class> createClass(Enhancer enhancer, Class> superclass) {
- Class> subclass = enhancer.createClass();
-
- Enhancer.registerCallbacks(subclass, callbackInstances.toArray(new Callback[] {}));
-
- return subclass;
- }
-
- /**
- * Works around a constraint imposed by the AspectJ 5 annotation-style programming model. See
- * comments inline for detail.
- *
- * @return original subclass instance unless superclass is annnotated with @Aspect, in which
- * case a subclass of the subclass is returned
- */
- private Class> nestOneClassDeeperIfAspect(Class> superclass, Class> origSubclass) {
- boolean superclassIsAnAspect = false;
-
- // check for @Aspect by name rather than by class literal to avoid
- // requiring AspectJ as a runtime dependency.
- for(Annotation anno : superclass.getAnnotations())
- if(anno.annotationType().getName().equals("org.aspectj.lang.annotation.Aspect"))
- superclassIsAnAspect = true;
-
- if(!superclassIsAnAspect)
- return origSubclass;
-
- // the superclass is annotated with AspectJ's @Aspect.
- // this means that we must create a subclass of the subclass
- // in order to avoid some guard logic in Spring core that disallows
- // extending a concrete aspect class.
- Enhancer enhancer = newEnhancer(origSubclass);
- enhancer.setStrategy(new DefaultGeneratorStrategy() {
- @Override
- protected byte[] transform(byte[] b) throws Exception {
- ClassWriter writer = new ClassWriter(false);
- ClassAdapter adapter =
- new AddAnnotationAdapter(writer, "Lorg/aspectj/lang/annotation/Aspect;");
- ClassReader reader = new ClassReader(b);
- reader.accept(adapter, false);
- return writer.toByteArray();
- }
- });
-
- // create a subclass of the original subclass
- Class> newSubclass = createClass(enhancer, origSubclass);
-
- return newSubclass;
- }
-
+ private static final Log log = LogFactory.getLog(ConfigurationEnhancer.class);
+
+ private final ArrayList> callbackTypes = new ArrayList>();
+
+ private final LinkedHashSet registrars = new LinkedHashSet();
+
+ private final ArrayList callbackInstances = new ArrayList();
+
+ private final CallbackFilter callbackFilter = new CallbackFilter() {
+ public int accept(Method candidateMethod) {
+ Iterator iter = registrars.iterator();
+ for (int i = 0; iter.hasNext(); i++)
+ if (iter.next().accepts(candidateMethod))
+ return i;
+
+ throw new IllegalStateException(format("No registrar is capable of "
+ + "handling method [%s]. Perhaps you forgot to add a catch-all registrar?",
+ candidateMethod.getName()));
+ }
+ };
+
+
+ /**
+ * Creates a new {@link ConfigurationEnhancer} instance.
+ */
+ public ConfigurationEnhancer(DefaultListableBeanFactory beanFactory, ConfigurationModel model) {
+ notNull(beanFactory, "beanFactory must be non-null");
+ notNull(model, "model must be non-null");
+
+ populateRegistrarsAndCallbacks(beanFactory, model);
+ }
+
+
+ /**
+ * Reads the contents of {@code model} in order to populate {@link #registrars},
+ * {@link #callbackInstances} and {@link #callbackTypes} appropriately.
+ *
+ * @see #callbackFilter
+ */
+ private void populateRegistrarsAndCallbacks(DefaultListableBeanFactory beanFactory,
+ ConfigurationModel model) {
+
+ for (ConfigurationClass configClass : model.getAllConfigurationClasses()) {
+ for (ModelMethod method : configClass.getMethods()) {
+ registrars.add(method.getRegistrar());
+
+ Callback callback = method.getCallback();
+
+ if (callback instanceof BeanFactoryAware)
+ ((BeanFactoryAware) callback).setBeanFactory(beanFactory);
+
+ callbackInstances.add(callback);
+ }
+ }
+
+ // register a 'catch-all' registrar
+ registrars.add(new BeanDefinitionRegistrar() {
+
+ public boolean accepts(Method method) {
+ return true;
+ }
+
+ public void register(ModelMethod method, BeanDefinitionRegistry registry) {
+ // no-op
+ }
+ });
+ callbackInstances.add(NoOp.INSTANCE);
+
+ for (Callback callback : callbackInstances)
+ callbackTypes.add(callback.getClass());
+ }
+
+
+ /**
+ * Loads the specified class and generates a CGLIB subclass of it equipped with
+ * container-aware callbacks capable of respecting scoping and other bean semantics.
+ *
+ * @return fully-qualified name of the enhanced subclass
+ */
+ public String enhance(String configClassName) {
+ if (log.isInfoEnabled())
+ log.info("Enhancing " + configClassName);
+
+ Class> superclass = loadRequiredClass(configClassName);
+
+ Class> subclass = createClass(newEnhancer(superclass), superclass);
+
+ subclass = nestOneClassDeeperIfAspect(superclass, subclass);
+
+ if (log.isInfoEnabled())
+ log.info(format("Successfully enhanced %s; enhanced class name is: %s", configClassName, subclass
+ .getName()));
+
+ return subclass.getName();
+ }
+
+ /**
+ * Creates a new CGLIB {@link Enhancer} instance.
+ */
+ private Enhancer newEnhancer(Class> superclass) {
+ Enhancer enhancer = new Enhancer();
+
+ // because callbackFilter and callbackTypes are dynamically populated
+ // there's no opportunity for caching. This does not appear to be causing
+ // any performance problem.
+ enhancer.setUseCache(false);
+
+ enhancer.setSuperclass(superclass);
+ enhancer.setUseFactory(false);
+ enhancer.setCallbackFilter(callbackFilter);
+ enhancer.setCallbackTypes(callbackTypes.toArray(new Class>[] {}));
+
+ return enhancer;
+ }
+
+ /**
+ * Uses enhancer to generate a subclass of superclass, ensuring that
+ * {@link #callbackInstances} are registered for the new subclass.
+ */
+ private Class> createClass(Enhancer enhancer, Class> superclass) {
+ Class> subclass = enhancer.createClass();
+
+ Enhancer.registerCallbacks(subclass, callbackInstances.toArray(new Callback[] {}));
+
+ return subclass;
+ }
+
+ /**
+ * Works around a constraint imposed by the AspectJ 5 annotation-style programming
+ * model. See comments inline for detail.
+ *
+ * @return original subclass instance unless superclass is annnotated with @Aspect, in
+ * which case a subclass of the subclass is returned
+ */
+ private Class> nestOneClassDeeperIfAspect(Class> superclass, Class> origSubclass) {
+ boolean superclassIsAnAspect = false;
+
+ // check for @Aspect by name rather than by class literal to avoid
+ // requiring AspectJ as a runtime dependency.
+ for (Annotation anno : superclass.getAnnotations())
+ if (anno.annotationType().getName().equals("org.aspectj.lang.annotation.Aspect"))
+ superclassIsAnAspect = true;
+
+ if (!superclassIsAnAspect)
+ return origSubclass;
+
+ // the superclass is annotated with AspectJ's @Aspect.
+ // this means that we must create a subclass of the subclass
+ // in order to avoid some guard logic in Spring core that disallows
+ // extending a concrete aspect class.
+ Enhancer enhancer = newEnhancer(origSubclass);
+ enhancer.setStrategy(new DefaultGeneratorStrategy() {
+ @Override
+ protected byte[] transform(byte[] b) throws Exception {
+ ClassWriter writer = new ClassWriter(false);
+ ClassAdapter adapter = new AddAnnotationAdapter(writer,
+ "Lorg/aspectj/lang/annotation/Aspect;");
+ ClassReader reader = new ClassReader(b);
+ reader.accept(adapter, false);
+ return writer.toByteArray();
+ }
+ });
+
+ // create a subclass of the original subclass
+ Class> newSubclass = createClass(enhancer, origSubclass);
+
+ return newSubclass;
+ }
+
}
diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/internal/parsing/AnnotationAdapter.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/internal/parsing/AnnotationAdapter.java
index 759a8f3b387..e7266ac0fe2 100644
--- a/org.springframework.config.java/src/main/java/org/springframework/config/java/internal/parsing/AnnotationAdapter.java
+++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/internal/parsing/AnnotationAdapter.java
@@ -19,48 +19,47 @@ import org.objectweb.asm.AnnotationVisitor;
/**
- * An empty AnnotationVisitor that delegates to another AnnotationVisitor.
- * This class can be used as a super class to quickly implement
- * useful annotation adapter classes, just by overriding the necessary
- * methods. Note that for some reason, ASM doesn't provide this class
- * (it does provide MethodAdapter and ClassAdapter), thus we're following
- * the general pattern and adding our own here.
- *
+ * An empty AnnotationVisitor that delegates to another AnnotationVisitor. This class can be
+ * used as a super class to quickly implement useful annotation adapter classes, just by
+ * overriding the necessary methods. Note that for some reason, ASM doesn't provide this
+ * class (it does provide MethodAdapter and ClassAdapter), thus we're following the general
+ * pattern and adding our own here.
+ *
* @author Chris Beams
*/
class AnnotationAdapter implements AnnotationVisitor {
- private AnnotationVisitor delegate;
+ private AnnotationVisitor delegate;
- /**
- * Creates a new AnnotationAdapter instance that will delegate
- * all its calls to delegate.
- *
- * @param delegate In most cases, the delegate will simply be
- * {@link AsmUtils#EMPTY_VISITOR}
- */
- public AnnotationAdapter(AnnotationVisitor delegate) {
- this.delegate = delegate;
- }
+ /**
+ * Creates a new AnnotationAdapter instance that will delegate all its calls to
+ * delegate.
+ *
+ * @param delegate In most cases, the delegate will simply be
+ * {@link AsmUtils#EMPTY_VISITOR}
+ */
+ public AnnotationAdapter(AnnotationVisitor delegate) {
+ this.delegate = delegate;
+ }
- public void visit(String arg0, Object arg1) {
- delegate.visit(arg0, arg1);
- }
+ public void visit(String arg0, Object arg1) {
+ delegate.visit(arg0, arg1);
+ }
- public AnnotationVisitor visitAnnotation(String arg0, String arg1) {
- return delegate.visitAnnotation(arg0, arg1);
- }
+ public AnnotationVisitor visitAnnotation(String arg0, String arg1) {
+ return delegate.visitAnnotation(arg0, arg1);
+ }
- public AnnotationVisitor visitArray(String arg0) {
- return delegate.visitArray(arg0);
- }
+ public AnnotationVisitor visitArray(String arg0) {
+ return delegate.visitArray(arg0);
+ }
- public void visitEnum(String arg0, String arg1, String arg2) {
- delegate.visitEnum(arg0, arg1, arg2);
- }
+ public void visitEnum(String arg0, String arg1, String arg2) {
+ delegate.visitEnum(arg0, arg1, arg2);
+ }
- public void visitEnd() {
- delegate.visitEnd();
- }
+ public void visitEnd() {
+ delegate.visitEnd();
+ }
}
diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/internal/parsing/AsmUtils.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/internal/parsing/AsmUtils.java
index 47929253b13..06764003195 100644
--- a/org.springframework.config.java/src/main/java/org/springframework/config/java/internal/parsing/AsmUtils.java
+++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/internal/parsing/AsmUtils.java
@@ -30,108 +30,115 @@ import org.springframework.config.java.Util;
*/
class AsmUtils {
- public static final EmptyVisitor EMPTY_VISITOR = new EmptyVisitor();
-
- private static final Log log = LogFactory.getLog(AsmUtils.class);
-
- /**
- * @param className a standard, dot-delimeted, fully-qualified Java class name
- * @return internal version of className, as per ASM guide section 2.1.2 "Internal Names"
- */
- public static String convertClassNameToInternalName(String className) {
- return className.replace('.', '/');
- }
-
- /**
- * Convert a type descriptor to a classname suitable for classloading
- * with Class.forName().
- *
- * @param typeDescriptor see ASM guide section 2.1.3
- */
- public static String convertTypeDescriptorToClassName(String typeDescriptor) {
- final String internalName; // See ASM guide section 2.1.2
-
- // TODO: SJC-242 should catch all possible cases. use case statement and switch on char
- // TODO: SJC-242 converting from primitive to object here won't be intuitive to users
- if("V".equals(typeDescriptor))
- return Void.class.getName();
- if("I".equals(typeDescriptor))
- return Integer.class.getName();
- if("Z".equals(typeDescriptor))
- return Boolean.class.getName();
-
- // strip the leading array/object/primitive identifier
- if(typeDescriptor.startsWith("[["))
- internalName = typeDescriptor.substring(3);
- else if(typeDescriptor.startsWith("["))
- internalName = typeDescriptor.substring(2);
- else
- internalName = typeDescriptor.substring(1);
-
- // convert slashes to dots
- String className = internalName.replace('/', '.');
-
- // and strip trailing semicolon (if present)
- if(className.endsWith(";"))
- className = className.substring(0, internalName.length()-1);
-
- return className;
- }
-
- /**
- * @param methodDescriptor see ASM guide section 2.1.4
- */
- public static String getReturnTypeFromMethodDescriptor(String methodDescriptor) {
- String returnTypeDescriptor = methodDescriptor.substring(methodDescriptor.indexOf(')')+1);
- return convertTypeDescriptorToClassName(returnTypeDescriptor);
- }
-
- /**
- * Creates a new ASM {@link ClassReader} for pathToClass. Appends '.class'
- * to pathToClass before attempting to load.
- *
- * @throws RuntimeException if pathToClass+.class cannot be found on the classpath
- * @throws RuntimeException if an IOException occurs when creating the new ClassReader
- */
- public static ClassReader newClassReader(String pathToClass) {
- InputStream is = Util.getClassAsStream(pathToClass);
- return newClassReader(is);
- }
-
- /**
- * Convenience method that simply returns a new ASM {@link ClassReader} instance based on
- * the supplied bytes byte array. This method is exactly equivalent to calling
- * new ClassReader(byte[]), and is mainly provided for symmetry with usage of
- * {@link #newClassReader(InputStream)}.
- *
- * @param bytes byte array that will be provided as input to the new ClassReader instance.
- *
- * @return
- */
- public static ClassReader newClassReader(byte[] bytes) {
- return new ClassReader(bytes);
- }
-
- /**
- * Convenience method that creates and returns a new ASM {@link ClassReader} for the given
- * InputStream is, closing the InputStream after creating the ClassReader and rethrowing
- * any IOException thrown during ClassReader instantiation as an unchecked exception. Logs and ignores
- * any IOException thrown when closing the InputStream.
- *
- * @param is InputStream that will be provided to the new ClassReader instance.
- */
- public static ClassReader newClassReader(InputStream is) {
- try {
- return new ClassReader(is);
- } catch (IOException ex) {
- throw new RuntimeException("An unexpected exception occurred while creating ASM ClassReader: " + ex);
- } finally {
- try {
- is.close();
- } catch (IOException ex) {
- log.error("Ignoring exception thrown while closing InputStream", ex);
- }
- }
- }
+ public static final EmptyVisitor EMPTY_VISITOR = new EmptyVisitor();
+
+ private static final Log log = LogFactory.getLog(AsmUtils.class);
+
+ /**
+ * @param className a standard, dot-delimeted, fully-qualified Java class name
+ * @return internal version of className, as per ASM guide section 2.1.2
+ * "Internal Names"
+ */
+ public static String convertClassNameToInternalName(String className) {
+ return className.replace('.', '/');
+ }
+
+ /**
+ * Convert a type descriptor to a classname suitable for classloading with
+ * Class.forName().
+ *
+ * @param typeDescriptor see ASM guide section 2.1.3
+ */
+ public static String convertTypeDescriptorToClassName(String typeDescriptor) {
+ final String internalName; // See ASM guide section 2.1.2
+
+ // TODO: SJC-242 should catch all possible cases. use case statement and switch on
+ // char
+ // TODO: SJC-242 converting from primitive to object here won't be intuitive to
+ // users
+ if ("V".equals(typeDescriptor))
+ return Void.class.getName();
+ if ("I".equals(typeDescriptor))
+ return Integer.class.getName();
+ if ("Z".equals(typeDescriptor))
+ return Boolean.class.getName();
+
+ // strip the leading array/object/primitive identifier
+ if (typeDescriptor.startsWith("[["))
+ internalName = typeDescriptor.substring(3);
+ else if (typeDescriptor.startsWith("["))
+ internalName = typeDescriptor.substring(2);
+ else
+ internalName = typeDescriptor.substring(1);
+
+ // convert slashes to dots
+ String className = internalName.replace('/', '.');
+
+ // and strip trailing semicolon (if present)
+ if (className.endsWith(";"))
+ className = className.substring(0, internalName.length() - 1);
+
+ return className;
+ }
+
+ /**
+ * @param methodDescriptor see ASM guide section 2.1.4
+ */
+ public static String getReturnTypeFromMethodDescriptor(String methodDescriptor) {
+ String returnTypeDescriptor = methodDescriptor.substring(methodDescriptor.indexOf(')') + 1);
+ return convertTypeDescriptorToClassName(returnTypeDescriptor);
+ }
+
+ /**
+ * Creates a new ASM {@link ClassReader} for pathToClass. Appends '.class' to
+ * pathToClass before attempting to load.
+ *
+ * @throws RuntimeException if pathToClass+.class cannot be found on the
+ * classpath
+ * @throws RuntimeException if an IOException occurs when creating the new ClassReader
+ */
+ public static ClassReader newClassReader(String pathToClass) {
+ InputStream is = Util.getClassAsStream(pathToClass);
+ return newClassReader(is);
+ }
+
+ /**
+ * Convenience method that simply returns a new ASM {@link ClassReader} instance based
+ * on the supplied bytes byte array. This method is exactly equivalent to
+ * calling new ClassReader(byte[]), and is mainly provided for symmetry with usage of
+ * {@link #newClassReader(InputStream)}.
+ *
+ * @param bytes byte array that will be provided as input to the new ClassReader
+ * instance.
+ *
+ * @return
+ */
+ public static ClassReader newClassReader(byte[] bytes) {
+ return new ClassReader(bytes);
+ }
+
+ /**
+ * Convenience method that creates and returns a new ASM {@link ClassReader} for the
+ * given InputStream is, closing the InputStream after creating the
+ * ClassReader and rethrowing any IOException thrown during ClassReader instantiation as
+ * an unchecked exception. Logs and ignores any IOException thrown when closing the
+ * InputStream.
+ *
+ * @param is InputStream that will be provided to the new ClassReader instance.
+ */
+ public static ClassReader newClassReader(InputStream is) {
+ try {
+ return new ClassReader(is);
+ } catch (IOException ex) {
+ throw new RuntimeException("An unexpected exception occurred while creating ASM ClassReader: "
+ + ex);
+ } finally {
+ try {
+ is.close();
+ } catch (IOException ex) {
+ log.error("Ignoring exception thrown while closing InputStream", ex);
+ }
+ }
+ }
}
diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/internal/parsing/ConfigurationClassMethodVisitor.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/internal/parsing/ConfigurationClassMethodVisitor.java
index 2fdda4f1478..d4d81861ae6 100644
--- a/org.springframework.config.java/src/main/java/org/springframework/config/java/internal/parsing/ConfigurationClassMethodVisitor.java
+++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/internal/parsing/ConfigurationClassMethodVisitor.java
@@ -34,113 +34,114 @@ import org.springframework.config.java.Factory;
import org.springframework.config.java.ModelClass;
import org.springframework.config.java.ModelMethod;
+
/**
- * Visits a single method declared in a given {@link Configuration} class. Determines whether the
- * method is a {@link Factory} method and if so, adds it to the {@link ConfigurationClass}.
+ * Visits a single method declared in a given {@link Configuration} class. Determines
+ * whether the method is a {@link Factory} method and if so, adds it to the
+ * {@link ConfigurationClass}.
*
* @author Chris Beams
*/
class ConfigurationClassMethodVisitor extends MethodAdapter {
- private final ConfigurationClass configClass;
- private final String methodName;
- private final int modifiers;
- private final ModelClass returnType;
- private final ArrayList annotations = new ArrayList();
-
- private boolean isModelMethod = false;
- private int lineNumber;
-
- /**
- * Creates a new {@link ConfigurationClassMethodVisitor} instance.
- *
- * @param configClass model object to which this method will be added
- * @param methodName name of the method declared in the {@link Configuration} class
- * @param methodDescriptor ASM representation of the method signature
- * @param modifiers modifiers for this method
- */
- public ConfigurationClassMethodVisitor(ConfigurationClass configClass, String methodName,
- String methodDescriptor, int modifiers) {
- super(AsmUtils.EMPTY_VISITOR);
-
- this.configClass = configClass;
- this.methodName = methodName;
- this.returnType = initReturnTypeFromMethodDescriptor(methodDescriptor);
- this.modifiers = modifiers;
- }
-
- /**
- * Visits a single annotation on this method. Will be called once for each
- * annotation present (regardless of its RetentionPolicy).
- */
- @Override
- public AnnotationVisitor visitAnnotation(String annoTypeDesc, boolean visible) {
- String annoClassName = AsmUtils.convertTypeDescriptorToClassName(annoTypeDesc);
-
- Class extends Annotation> annoClass = loadToolingSafeClass(annoClassName);
-
- if(annoClass == null)
- return super.visitAnnotation(annoTypeDesc, visible);
-
- Annotation annotation = createMutableAnnotation(annoClass);
-
- annotations.add(annotation);
-
- return new MutableAnnotationVisitor(annotation);
- }
-
- /**
- * Provides the line number of this method within its declaring class. In reality,
- * this number is always inaccurate - lineNo represents the line number
- * of the first instruction in this method. Method declaration line numbers are
- * not in any way tracked in the bytecode. Any tooling or output that reads this
- * value will have to compensate and estimate where the actual method declaration
- * is.
- */
- @Override
- public void visitLineNumber(int lineNo, Label start) {
- this.lineNumber = lineNo;
- }
-
- /**
- * Parses through all {@link #annotations} on this method in order to determine whether
- * it is a {@link Factory} method or not and if so adds it to the
- * enclosing {@link #configClass}.
- */
- @Override
- public void visitEnd() {
- for(Annotation anno : annotations) {
- if(anno.annotationType().getAnnotation(Factory.class) != null) {
- isModelMethod = true;
- break;
- }
- }
-
- if(!isModelMethod)
- return;
-
- Annotation[] annoArray = annotations.toArray(new Annotation[] { });
- ModelMethod method = new ModelMethod(methodName, modifiers, returnType, annoArray);
- method.setLineNumber(lineNumber);
- configClass.addMethod(method);
- }
-
- /**
- * Determines return type from ASM methodDescriptor and determines whether
- * that type is an interface.
- */
- private static ModelClass initReturnTypeFromMethodDescriptor(String methodDescriptor) {
- final ModelClass returnType = new ModelClass(getReturnTypeFromMethodDescriptor(methodDescriptor));
-
- // detect whether the return type is an interface
- newClassReader(convertClassNameToResourcePath(returnType.getName())).accept(
- new ClassAdapter(AsmUtils.EMPTY_VISITOR) {
- @Override
- public void visit(int arg0, int arg1, String arg2, String arg3, String arg4, String[] arg5) {
- returnType.setInterface((arg1 & Opcodes.ACC_INTERFACE) == Opcodes.ACC_INTERFACE);
- }
- }, false);
-
- return returnType;
- }
+ private final ConfigurationClass configClass;
+ private final String methodName;
+ private final int modifiers;
+ private final ModelClass returnType;
+ private final ArrayList annotations = new ArrayList();
+
+ private boolean isModelMethod = false;
+ private int lineNumber;
+
+ /**
+ * Creates a new {@link ConfigurationClassMethodVisitor} instance.
+ *
+ * @param configClass model object to which this method will be added
+ * @param methodName name of the method declared in the {@link Configuration} class
+ * @param methodDescriptor ASM representation of the method signature
+ * @param modifiers modifiers for this method
+ */
+ public ConfigurationClassMethodVisitor(ConfigurationClass configClass, String methodName,
+ String methodDescriptor, int modifiers) {
+ super(AsmUtils.EMPTY_VISITOR);
+
+ this.configClass = configClass;
+ this.methodName = methodName;
+ this.returnType = initReturnTypeFromMethodDescriptor(methodDescriptor);
+ this.modifiers = modifiers;
+ }
+
+ /**
+ * Visits a single annotation on this method. Will be called once for each annotation
+ * present (regardless of its RetentionPolicy).
+ */
+ @Override
+ public AnnotationVisitor visitAnnotation(String annoTypeDesc, boolean visible) {
+ String annoClassName = AsmUtils.convertTypeDescriptorToClassName(annoTypeDesc);
+
+ Class extends Annotation> annoClass = loadToolingSafeClass(annoClassName);
+
+ if (annoClass == null)
+ return super.visitAnnotation(annoTypeDesc, visible);
+
+ Annotation annotation = createMutableAnnotation(annoClass);
+
+ annotations.add(annotation);
+
+ return new MutableAnnotationVisitor(annotation);
+ }
+
+ /**
+ * Provides the line number of this method within its declaring class. In reality, this
+ * number is always inaccurate - lineNo represents the line number of the
+ * first instruction in this method. Method declaration line numbers are not in any way
+ * tracked in the bytecode. Any tooling or output that reads this value will have to
+ * compensate and estimate where the actual method declaration is.
+ */
+ @Override
+ public void visitLineNumber(int lineNo, Label start) {
+ this.lineNumber = lineNo;
+ }
+
+ /**
+ * Parses through all {@link #annotations} on this method in order to determine whether
+ * it is a {@link Factory} method or not and if so adds it to the enclosing
+ * {@link #configClass}.
+ */
+ @Override
+ public void visitEnd() {
+ for (Annotation anno : annotations) {
+ if (anno.annotationType().getAnnotation(Factory.class) != null) {
+ isModelMethod = true;
+ break;
+ }
+ }
+
+ if (!isModelMethod)
+ return;
+
+ Annotation[] annoArray = annotations.toArray(new Annotation[] {});
+ ModelMethod method = new ModelMethod(methodName, modifiers, returnType, annoArray);
+ method.setLineNumber(lineNumber);
+ configClass.addMethod(method);
+ }
+
+ /**
+ * Determines return type from ASM methodDescriptor and determines whether
+ * that type is an interface.
+ */
+ private static ModelClass initReturnTypeFromMethodDescriptor(String methodDescriptor) {
+ final ModelClass returnType = new ModelClass(getReturnTypeFromMethodDescriptor(methodDescriptor));
+
+ // detect whether the return type is an interface
+ newClassReader(convertClassNameToResourcePath(returnType.getName())).accept(
+ new ClassAdapter(AsmUtils.EMPTY_VISITOR) {
+ @Override
+ public void visit(int arg0, int arg1, String arg2, String arg3, String arg4, String[] arg5) {
+ returnType.setInterface((arg1 & Opcodes.ACC_INTERFACE) == Opcodes.ACC_INTERFACE);
+ }
+ }, false);
+
+ return returnType;
+ }
}
diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/internal/parsing/ConfigurationClassVisitor.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/internal/parsing/ConfigurationClassVisitor.java
index 016effa90ee..d4f2bf65f1f 100644
--- a/org.springframework.config.java/src/main/java/org/springframework/config/java/internal/parsing/ConfigurationClassVisitor.java
+++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/internal/parsing/ConfigurationClassVisitor.java
@@ -37,198 +37,196 @@ import org.springframework.util.ClassUtils;
/**
- * Visits a {@link Configuration} class, populating a {@link ConfigurationClass} instance with
- * information gleaned along the way.
+ * Visits a {@link Configuration} class, populating a {@link ConfigurationClass} instance
+ * with information gleaned along the way.
*
* @author Chris Beams
*/
class ConfigurationClassVisitor extends ClassAdapter {
- private static final Log log = LogFactory.getLog(ConfigurationClassVisitor.class);
- private static final String OBJECT_DESC = convertClassNameToResourcePath(Object.class.getName());
-
- private final ConfigurationClass configClass;
- private final ConfigurationModel model;
- private final HashMap innerClasses = new HashMap();
-
- private boolean processInnerClasses = true;
-
- public ConfigurationClassVisitor(ConfigurationClass configClass, ConfigurationModel model) {
- super(AsmUtils.EMPTY_VISITOR);
- this.configClass = configClass;
- this.model = model;
- }
-
- public void setProcessInnerClasses(boolean processInnerClasses) {
- this.processInnerClasses = processInnerClasses;
- }
-
- @Override
- public void visitSource(String sourceFile, String debug) {
- String resourcePath =
- convertClassNameToResourcePath(configClass.getName())
- .substring(0, configClass.getName().lastIndexOf('.')+1)
- .concat(sourceFile);
-
- configClass.setSource(resourcePath);
- }
-
- @Override
- public void visit(int classVersion, int modifiers, String classTypeDesc, String arg3,
- String superTypeDesc, String[] arg5) {
- visitSuperType(superTypeDesc);
-
- configClass.setName(convertResourcePathToClassName(classTypeDesc));
-
- // ASM always adds ACC_SUPER to the opcodes/modifiers for class definitions.
- // Unknown as to why (JavaDoc is silent on the matter), but it should be
- // eliminated in order to comply with java.lang.reflect.Modifier values.
- configClass.setModifiers(modifiers - Opcodes.ACC_SUPER);
- }
-
- private void visitSuperType(String superTypeDesc) {
- // traverse up the type hierarchy unless the next ancestor is java.lang.Object
- if(OBJECT_DESC.equals(superTypeDesc))
- return;
-
- ConfigurationClassVisitor visitor = new ConfigurationClassVisitor(configClass, model);
-
- ClassReader reader = AsmUtils.newClassReader(superTypeDesc);
- reader.accept(visitor, false);
- }
-
- /**
- * Visits a class level annotation on a {@link Configuration @Configuration} class.
- * Accounts for all possible class-level annotations that are respected by JavaConfig
- * including AspectJ's {@code @Aspect} annotation.
- *
- * Upon encountering such an annotation, update the {@link #configClass} model object
- * appropriately, and then return an {@link AnnotationVisitor} implementation that can
- * populate the annotation appropriately with data.
- *
- * @see MutableAnnotation
- */
- @Override
- public AnnotationVisitor visitAnnotation(String annoTypeDesc, boolean visible) {
- String annoTypeName = AsmUtils.convertTypeDescriptorToClassName(annoTypeDesc);
-
- if (Configuration.class.getName().equals(annoTypeName)) {
- Configuration mutableConfiguration = createMutableAnnotation(Configuration.class);
- configClass.setMetadata(mutableConfiguration);
- return new MutableAnnotationVisitor(mutableConfiguration);
- }
-
- // TODO: re-enable for @Import support
-// if (Import.class.getName().equals(annoTypeName)) {
-// ImportStack importStack = ImportStackHolder.getImportStack();
-//
-// if(importStack.contains(configClass))
-// throw new CircularImportException(configClass, importStack);
-//
-// importStack.push(configClass);
-//
-// return new ImportAnnotationVisitor(model);
-// }
-
- // -------------------------------------
- // Detect @Plugin annotations
- // -------------------------------------
- PluginAnnotationDetectingClassVisitor classVisitor = new PluginAnnotationDetectingClassVisitor();
-
- String className = AsmUtils.convertTypeDescriptorToClassName(annoTypeDesc);
- String resourcePath = ClassUtils.convertClassNameToResourcePath(className);
- ClassReader reader = AsmUtils.newClassReader(resourcePath);
- reader.accept(classVisitor, false);
-
- if(!classVisitor.hasPluginAnnotation())
- return super.visitAnnotation(annoTypeDesc, visible);
-
- Class extends Annotation> annoType = loadToolingSafeClass(annoTypeName);
-
- if(annoType == null)
- return super.visitAnnotation(annoTypeDesc, visible);
-
- Annotation pluginAnno = createMutableAnnotation(annoType);
- configClass.addPluginAnnotation(pluginAnno);
- return new MutableAnnotationVisitor(pluginAnno);
- }
-
- private static class PluginAnnotationDetectingClassVisitor extends ClassAdapter {
- private boolean hasPluginAnnotation = false;
- private final Extension pluginAnnotation = createMutableAnnotation(Extension.class);
-
- public PluginAnnotationDetectingClassVisitor() {
- super(AsmUtils.EMPTY_VISITOR);
- }
-
- @Override
- public AnnotationVisitor visitAnnotation(String typeDesc, boolean arg1) {
- if(Extension.class.getName().equals(AsmUtils.convertTypeDescriptorToClassName(typeDesc))) {
- hasPluginAnnotation = true;
- return new MutableAnnotationVisitor(pluginAnnotation);
- }
- return super.visitAnnotation(typeDesc, arg1);
- }
-
- public boolean hasPluginAnnotation() {
- return hasPluginAnnotation;
- }
-
- public Extension getPluginAnnotation() {
- return pluginAnnotation;
- }
- }
-
- /**
- * Delegates all {@link Configuration @Configuration} class method parsing to
- * {@link ConfigurationClassMethodVisitor}.
- */
- @Override
- public MethodVisitor visitMethod(int modifiers, String methodName, String methodDescriptor,
- String arg3, String[] arg4) {
-
- return new ConfigurationClassMethodVisitor(configClass, methodName, methodDescriptor, modifiers);
- }
-
- /**
- * Implementation deals with inner classes here even though it would have
- * been more intuitive to deal with outer classes. Due to limitations in ASM
- * (resulting from limitations in the VM spec) we cannot directly look for outer classes
- * in all cases, so instead build up a model of {@link #innerClasses} and process
- * declaring class logic in a kind of inverted manner.
- */
- @Override
- public void visitInnerClass(String name, String outerName, String innerName, int access) {
- if(processInnerClasses == false)
- return;
-
- String innerClassName = convertResourcePathToClassName(name);
- String configClassName = configClass.getName();
-
- // if the innerClassName is equal to configClassName, we just
- // ran into the outermost inner class look up the outer class
- // associated with this
- if(innerClassName.equals(configClassName)) {
- if(innerClasses.containsKey(outerName)) {
- configClass.setDeclaringClass(innerClasses.get(outerName));
- }
- return;
- }
-
- ConfigurationClass innerConfigClass = new ConfigurationClass();
-
- ConfigurationClassVisitor ccVisitor =
- new ConfigurationClassVisitor(innerConfigClass, new ConfigurationModel());
- ccVisitor.setProcessInnerClasses(false);
-
- ClassReader reader = AsmUtils.newClassReader(name);
- reader.accept(ccVisitor, false);
-
- if(innerClasses.containsKey(outerName))
- innerConfigClass.setDeclaringClass(innerClasses.get(outerName));
-
- // is the inner class a @Configuration class? If so, add it to the list
- if(innerConfigClass.getMetadata() != null)
- innerClasses.put(name, innerConfigClass);
- }
+ private static final Log log = LogFactory.getLog(ConfigurationClassVisitor.class);
+ private static final String OBJECT_DESC = convertClassNameToResourcePath(Object.class.getName());
+
+ private final ConfigurationClass configClass;
+ private final ConfigurationModel model;
+ private final HashMap innerClasses = new HashMap();
+
+ private boolean processInnerClasses = true;
+
+ public ConfigurationClassVisitor(ConfigurationClass configClass, ConfigurationModel model) {
+ super(AsmUtils.EMPTY_VISITOR);
+ this.configClass = configClass;
+ this.model = model;
+ }
+
+ public void setProcessInnerClasses(boolean processInnerClasses) {
+ this.processInnerClasses = processInnerClasses;
+ }
+
+ @Override
+ public void visitSource(String sourceFile, String debug) {
+ String resourcePath = convertClassNameToResourcePath(configClass.getName()).substring(0,
+ configClass.getName().lastIndexOf('.') + 1).concat(sourceFile);
+
+ configClass.setSource(resourcePath);
+ }
+
+ @Override
+ public void visit(int classVersion, int modifiers, String classTypeDesc, String arg3,
+ String superTypeDesc, String[] arg5) {
+ visitSuperType(superTypeDesc);
+
+ configClass.setName(convertResourcePathToClassName(classTypeDesc));
+
+ // ASM always adds ACC_SUPER to the opcodes/modifiers for class definitions.
+ // Unknown as to why (JavaDoc is silent on the matter), but it should be
+ // eliminated in order to comply with java.lang.reflect.Modifier values.
+ configClass.setModifiers(modifiers - Opcodes.ACC_SUPER);
+ }
+
+ private void visitSuperType(String superTypeDesc) {
+ // traverse up the type hierarchy unless the next ancestor is java.lang.Object
+ if (OBJECT_DESC.equals(superTypeDesc))
+ return;
+
+ ConfigurationClassVisitor visitor = new ConfigurationClassVisitor(configClass, model);
+
+ ClassReader reader = AsmUtils.newClassReader(superTypeDesc);
+ reader.accept(visitor, false);
+ }
+
+ /**
+ * Visits a class level annotation on a {@link Configuration @Configuration} class.
+ * Accounts for all possible class-level annotations that are respected by JavaConfig
+ * including AspectJ's {@code @Aspect} annotation.
+ *
+ * Upon encountering such an annotation, update the {@link #configClass} model object
+ * appropriately, and then return an {@link AnnotationVisitor} implementation that can
+ * populate the annotation appropriately with data.
+ *
+ * @see MutableAnnotation
+ */
+ @Override
+ public AnnotationVisitor visitAnnotation(String annoTypeDesc, boolean visible) {
+ String annoTypeName = AsmUtils.convertTypeDescriptorToClassName(annoTypeDesc);
+
+ if (Configuration.class.getName().equals(annoTypeName)) {
+ Configuration mutableConfiguration = createMutableAnnotation(Configuration.class);
+ configClass.setMetadata(mutableConfiguration);
+ return new MutableAnnotationVisitor(mutableConfiguration);
+ }
+
+ // TODO: re-enable for @Import support
+ // if (Import.class.getName().equals(annoTypeName)) {
+ // ImportStack importStack = ImportStackHolder.getImportStack();
+ //
+ // if(importStack.contains(configClass))
+ // throw new CircularImportException(configClass, importStack);
+ //
+ // importStack.push(configClass);
+ //
+ // return new ImportAnnotationVisitor(model);
+ // }
+
+ // -------------------------------------
+ // Detect @Plugin annotations
+ // -------------------------------------
+ PluginAnnotationDetectingClassVisitor classVisitor = new PluginAnnotationDetectingClassVisitor();
+
+ String className = AsmUtils.convertTypeDescriptorToClassName(annoTypeDesc);
+ String resourcePath = ClassUtils.convertClassNameToResourcePath(className);
+ ClassReader reader = AsmUtils.newClassReader(resourcePath);
+ reader.accept(classVisitor, false);
+
+ if (!classVisitor.hasPluginAnnotation())
+ return super.visitAnnotation(annoTypeDesc, visible);
+
+ Class extends Annotation> annoType = loadToolingSafeClass(annoTypeName);
+
+ if (annoType == null)
+ return super.visitAnnotation(annoTypeDesc, visible);
+
+ Annotation pluginAnno = createMutableAnnotation(annoType);
+ configClass.addPluginAnnotation(pluginAnno);
+ return new MutableAnnotationVisitor(pluginAnno);
+ }
+
+ private static class PluginAnnotationDetectingClassVisitor extends ClassAdapter {
+ private boolean hasPluginAnnotation = false;
+ private final Extension pluginAnnotation = createMutableAnnotation(Extension.class);
+
+ public PluginAnnotationDetectingClassVisitor() {
+ super(AsmUtils.EMPTY_VISITOR);
+ }
+
+ @Override
+ public AnnotationVisitor visitAnnotation(String typeDesc, boolean arg1) {
+ if (Extension.class.getName().equals(AsmUtils.convertTypeDescriptorToClassName(typeDesc))) {
+ hasPluginAnnotation = true;
+ return new MutableAnnotationVisitor(pluginAnnotation);
+ }
+ return super.visitAnnotation(typeDesc, arg1);
+ }
+
+ public boolean hasPluginAnnotation() {
+ return hasPluginAnnotation;
+ }
+
+ public Extension getPluginAnnotation() {
+ return pluginAnnotation;
+ }
+ }
+
+ /**
+ * Delegates all {@link Configuration @Configuration} class method parsing to
+ * {@link ConfigurationClassMethodVisitor}.
+ */
+ @Override
+ public MethodVisitor visitMethod(int modifiers, String methodName, String methodDescriptor, String arg3,
+ String[] arg4) {
+
+ return new ConfigurationClassMethodVisitor(configClass, methodName, methodDescriptor, modifiers);
+ }
+
+ /**
+ * Implementation deals with inner classes here even though it would have been more
+ * intuitive to deal with outer classes. Due to limitations in ASM (resulting from
+ * limitations in the VM spec) we cannot directly look for outer classes in all cases,
+ * so instead build up a model of {@link #innerClasses} and process declaring class
+ * logic in a kind of inverted manner.
+ */
+ @Override
+ public void visitInnerClass(String name, String outerName, String innerName, int access) {
+ if (processInnerClasses == false)
+ return;
+
+ String innerClassName = convertResourcePathToClassName(name);
+ String configClassName = configClass.getName();
+
+ // if the innerClassName is equal to configClassName, we just
+ // ran into the outermost inner class look up the outer class
+ // associated with this
+ if (innerClassName.equals(configClassName)) {
+ if (innerClasses.containsKey(outerName)) {
+ configClass.setDeclaringClass(innerClasses.get(outerName));
+ }
+ return;
+ }
+
+ ConfigurationClass innerConfigClass = new ConfigurationClass();
+
+ ConfigurationClassVisitor ccVisitor = new ConfigurationClassVisitor(innerConfigClass,
+ new ConfigurationModel());
+ ccVisitor.setProcessInnerClasses(false);
+
+ ClassReader reader = AsmUtils.newClassReader(name);
+ reader.accept(ccVisitor, false);
+
+ if (innerClasses.containsKey(outerName))
+ innerConfigClass.setDeclaringClass(innerClasses.get(outerName));
+
+ // is the inner class a @Configuration class? If so, add it to the list
+ if (innerConfigClass.getMetadata() != null)
+ innerClasses.put(name, innerConfigClass);
+ }
}
diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/internal/parsing/MutableAnnotation.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/internal/parsing/MutableAnnotation.java
index 65d68385f21..6fc66f390ef 100644
--- a/org.springframework.config.java/src/main/java/org/springframework/config/java/internal/parsing/MutableAnnotation.java
+++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/internal/parsing/MutableAnnotation.java
@@ -16,16 +16,15 @@
package org.springframework.config.java.internal.parsing;
/**
- * Note: the visibility of this interface would be reduced to package-private
- * save for an obscure restriction of JDK dynamic proxies.
- * {@link MutableAnnotationUtils#createMutableAnnotation(Class)} creates a proxy
- * based on two interfaces: this one, and whatever annotation is currently being
- * parsed. The restriction is that both interfaces may not be package-private if
- * they are in separate packages. In order to avoid unnecessarily restricting
- * the visibility options for user-defined annotations, this interface becomes
- * public. Because it is in the internal.* package, it won't pollute the public
- * API, but developers should take caution not to use this annotation outside
- * the internal.parsing package.
+ * Note: the visibility of this interface would be reduced to package-private save for an
+ * obscure restriction of JDK dynamic proxies.
+ * {@link MutableAnnotationUtils#createMutableAnnotation(Class)} creates a proxy based on
+ * two interfaces: this one, and whatever annotation is currently being parsed. The
+ * restriction is that both interfaces may not be package-private if they are in separate
+ * packages. In order to avoid unnecessarily restricting the visibility options for
+ * user-defined annotations, this interface becomes public. Because it is in the internal.*
+ * package, it won't pollute the public API, but developers should take caution not to use
+ * this annotation outside the internal.parsing package.
*
* @author Chris Beams
*/
diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/internal/parsing/MutableAnnotationArrayVisitor.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/internal/parsing/MutableAnnotationArrayVisitor.java
index b67f034e4cc..e5cba8fb165 100644
--- a/org.springframework.config.java/src/main/java/org/springframework/config/java/internal/parsing/MutableAnnotationArrayVisitor.java
+++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/internal/parsing/MutableAnnotationArrayVisitor.java
@@ -29,43 +29,43 @@ import org.objectweb.asm.AnnotationVisitor;
/** TODO: JAVADOC */
class MutableAnnotationArrayVisitor extends AnnotationAdapter {
-
- private static final Log log = LogFactory.getLog(MutableAnnotationArrayVisitor.class);
-
- private final ArrayList
- *
- * Conforms strictly to the equals() specification for Annotation
- *
- * @see Annotation#equals(Object)
- */
- private Object isEqualTo(Object proxy, Object other) {
- if (proxy == other)
- return true;
-
- if (other == null)
- return false;
-
- if(!annoType.isAssignableFrom(other.getClass()))
- return false;
-
- for (String attribName : attributes.keySet()) {
- Object thisVal;
- Object thatVal;
-
- try {
- thisVal = attributes.get(attribName);
- thatVal = other.getClass().getDeclaredMethod(attribName).invoke(other);
- } catch (Exception ex) {
- throw new RuntimeException(ex);
- }
-
- if ((thisVal == null) && (thatVal != null))
- return false;
-
- if ((thatVal == null) && (thisVal != null))
- return false;
-
- if (thatVal.getClass().isArray()) {
- if (!Arrays.equals((Object[]) thatVal, (Object[]) thisVal)) {
- return false;
- }
- } else if (thisVal instanceof Double) {
- if (!Double.valueOf((Double) thisVal).equals(Double.valueOf((Double) thatVal)))
- return false;
- } else if (thisVal instanceof Float) {
- if (!Float.valueOf((Float) thisVal).equals(Float.valueOf((Float) thatVal)))
- return false;
- } else if (!thisVal.equals(thatVal)) {
- return false;
- }
- }
-
- return true;
- }
-
- private String getAttribs() {
- ArrayList attribs = new ArrayList();
-
- for (String attribName : attributes.keySet())
- attribs.add(format("%s=%s", attribName, attributes.get(attribName)));
-
- return StringUtils.collectionToDelimitedString(attribs, ", ");
- }
-
- /**
- * Retrieve the type of the given annotation attribute.
- */
- private static Class> getAttributeType(Class extends Annotation> annotationType, String attributeName) {
- Method method = null;
-
- try {
- method = annotationType.getDeclaredMethod(attributeName);
- }
- catch (Exception ex) {
- ReflectionUtils.handleReflectionException(ex);
- }
-
- return method.getReturnType();
- }
+ private final Class extends Annotation> annoType;
+ private final HashMap attributes = new HashMap();
+ private final HashMap> attributeTypes = new HashMap>();
+
+ public MutableAnnotationInvocationHandler(Class extends Annotation> annoType) {
+ // pre-populate the attributes hash will all the names
+ // and default values of the attributes defined in 'annoType'
+ Method[] attribs = annoType.getDeclaredMethods();
+ for (Method attrib : attribs) {
+ this.attributes.put(attrib.getName(), getDefaultValue(annoType, attrib.getName()));
+ this.attributeTypes.put(attrib.getName(), getAttributeType(annoType, attrib.getName()));
+ }
+
+ this.annoType = annoType;
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ Assert.isInstanceOf(Annotation.class, proxy);
+
+ String methodName = method.getName();
+
+ // first -> check to see if this method is an attribute on our annotation
+ if (attributes.containsKey(methodName))
+ return attributes.get(methodName);
+
+
+ // second -> is it a method from java.lang.annotation.Annotation?
+ if (methodName.equals("annotationType"))
+ return annoType;
+
+
+ // third -> is it a method from java.lang.Object?
+ if (methodName.equals("toString"))
+ return format("@%s(%s)", annoType.getName(), getAttribs());
+
+ if (methodName.equals("equals"))
+ return isEqualTo(proxy, args[0]);
+
+ if (methodName.equals("hashCode"))
+ return calculateHashCode(proxy);
+
+
+ // finally -> is it a method specified by MutableAnno?
+ if (methodName.equals("setAttributeValue")) {
+ attributes.put((String) args[0], args[1]);
+ return null; // setAttributeValue has a 'void' return type
+ }
+
+ if (methodName.equals("getAttributeType"))
+ return attributeTypes.get(args[0]);
+
+ throw new UnsupportedOperationException("this proxy does not support method: " + methodName);
+ }
+
+ /**
+ * Conforms to the hashCode() specification for Annotation.
+ *
+ * @see Annotation#hashCode()
+ */
+ private Object calculateHashCode(Object proxy) {
+ int sum = 0;
+
+ for (String attribName : attributes.keySet()) {
+ Object attribValue = attributes.get(attribName);
+
+ final int attribNameHashCode = attribName.hashCode();
+ final int attribValueHashCode;
+
+ if (attribValue == null)
+ // memberValue may be null when a mutable annotation is being added to a
+ // collection
+ // and before it has actually been visited (and populated) by
+ // MutableAnnotationVisitor
+ attribValueHashCode = 0;
+ else if (attribValue.getClass().isArray())
+ attribValueHashCode = Arrays.hashCode((Object[]) attribValue);
+ else
+ attribValueHashCode = attribValue.hashCode();
+
+ sum += (127 * attribNameHashCode) ^ attribValueHashCode;
+ }
+
+ return sum;
+ }
+
+ /**
+ * Compares proxy object and other object by comparing the return
+ * values of the methods specified by their common {@link Annotation} ancestry.
+ *
+ * other must be the same type as or a subtype of proxy. Will
+ * return false otherwise.
+ *
+ * Eagerly returns true if {@code proxy} == other
+ *
+ *
+ * Conforms strictly to the equals() specification for Annotation
+ *