+ Eliminated UsageError/Validatable/MalformedConfigurationException in favor of existing Problem/ProblemReporter types
+ Pruned a number of attributes from the @Bean and @Configuration annotations
This commit is contained in:
parent
c41c64389f
commit
100ba6599f
|
|
@ -22,10 +22,6 @@ import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowire;
|
|
||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
|
||||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Annotation to be applied to methods that create beans in a Spring context. The name of
|
* Annotation to be applied to methods that create beans in a Spring context. The name of
|
||||||
|
|
@ -65,33 +61,39 @@ import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||||
@Documented
|
@Documented
|
||||||
public @interface Bean {
|
public @interface Bean {
|
||||||
|
|
||||||
/**
|
// TODO:
|
||||||
* Role this bean plays in the overall application configuration.
|
// /**
|
||||||
*
|
// * Role this bean plays in the overall application configuration.
|
||||||
* @see BeanDefinition#ROLE_APPLICATION
|
// *
|
||||||
* @see BeanDefinition#ROLE_INFRASTRUCTURE
|
// * @see BeanDefinition#ROLE_APPLICATION
|
||||||
* @see BeanDefinition#ROLE_SUPPORT
|
// * @see BeanDefinition#ROLE_INFRASTRUCTURE
|
||||||
*
|
// * @see BeanDefinition#ROLE_SUPPORT
|
||||||
* @see AbstractBeanDefinition the 'role' field is assigned by default to
|
// *
|
||||||
* ROLE_APPLICATION
|
// * @see AbstractBeanDefinition the 'role' field is assigned by default to
|
||||||
*/
|
// * ROLE_APPLICATION
|
||||||
int role() default BeanDefinition.ROLE_APPLICATION;
|
// */
|
||||||
|
// int role() default BeanDefinition.ROLE_APPLICATION;
|
||||||
|
|
||||||
/**
|
String[] name() default {};
|
||||||
* Bean aliases.
|
|
||||||
*/
|
|
||||||
String[] aliases() default {};
|
|
||||||
|
|
||||||
/**
|
// TODO: Prune aliases, favor name[]
|
||||||
* Scope: whether the bean is a singleton, prototype or custom scope. Default is
|
// /**
|
||||||
* singleton.
|
// * Bean aliases.
|
||||||
*/
|
// */
|
||||||
String scope() default StandardScopes.SINGLETON;
|
// String[] aliases() default {};
|
||||||
|
|
||||||
/**
|
// TODO: favor @Scope
|
||||||
* Bean autowire strategy.
|
// /**
|
||||||
*/
|
// * Scope: whether the bean is a singleton, prototype or custom scope. Default is
|
||||||
Autowire autowire() default Autowire.INHERITED;
|
// * singleton.
|
||||||
|
// */
|
||||||
|
// String scope() default StandardScopes.SINGLETON;
|
||||||
|
|
||||||
|
// TODO: prune autowiring?
|
||||||
|
// /**
|
||||||
|
// * Bean autowire strategy.
|
||||||
|
// */
|
||||||
|
// Autowire autowire() default Autowire.INHERITED;
|
||||||
|
|
||||||
// /**
|
// /**
|
||||||
// * Bean lazy strategy.
|
// * Bean lazy strategy.
|
||||||
|
|
@ -111,13 +113,14 @@ public @interface Bean {
|
||||||
* Bean init method name. Normally this is not needed, as the initialization (with
|
* Bean init method name. Normally this is not needed, as the initialization (with
|
||||||
* parameterization) can be done directly through java code.
|
* parameterization) can be done directly through java code.
|
||||||
*/
|
*/
|
||||||
String initMethodName() default "";
|
String initMethod() default "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bean destroy method name.
|
* Bean destroy method name.
|
||||||
*/
|
*/
|
||||||
String destroyMethodName() default "";
|
String destroyMethod() default "";
|
||||||
|
|
||||||
|
// TODO: Prune DependencyCheck
|
||||||
// /**
|
// /**
|
||||||
// * Bean dependency check strategy.
|
// * Bean dependency check strategy.
|
||||||
// */
|
// */
|
||||||
|
|
@ -128,19 +131,23 @@ public @interface Bean {
|
||||||
*/
|
*/
|
||||||
String[] dependsOn() default {};
|
String[] dependsOn() default {};
|
||||||
|
|
||||||
|
// TODO: Prune @Meta
|
||||||
// /**
|
// /**
|
||||||
// * Metadata for the current bean.
|
// * Metadata for the current bean.
|
||||||
// */
|
// */
|
||||||
// Meta[] meta() default { };
|
// Meta[] meta() default { };
|
||||||
|
|
||||||
/**
|
// TODO: Prune allowOverriding
|
||||||
* Allow the bean to be overridden in another JavaConfig, XML or other non-Java
|
// /**
|
||||||
* configuration. This is consistent with DefaultListableBeanFactory's
|
// * Allow the bean to be overridden in another JavaConfig, XML or other non-Java
|
||||||
* allowBeanDefinitionOverriding property, which defaults to true.
|
// * configuration. This is consistent with DefaultListableBeanFactory's
|
||||||
*
|
// * allowBeanDefinitionOverriding property, which defaults to true.
|
||||||
* @return whether overriding of this bean is allowed
|
// *
|
||||||
*/
|
// * @return whether overriding of this bean is allowed
|
||||||
boolean allowOverriding() default true;
|
// */
|
||||||
|
// boolean allowOverriding() default true;
|
||||||
|
//
|
||||||
|
//String name() default "";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,16 +16,22 @@
|
||||||
package org.springframework.config.java;
|
package org.springframework.config.java;
|
||||||
|
|
||||||
import static java.lang.String.*;
|
import static java.lang.String.*;
|
||||||
|
import static org.springframework.config.java.StandardScopes.*;
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.parsing.Location;
|
||||||
|
import org.springframework.beans.factory.parsing.Problem;
|
||||||
|
import org.springframework.beans.factory.parsing.ProblemReporter;
|
||||||
|
import org.springframework.context.annotation.Scope;
|
||||||
|
import org.springframework.core.io.FileSystemResource;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
|
||||||
public final class BeanMethod implements Validatable {
|
public final class BeanMethod {
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
private final int modifiers;
|
private final int modifiers;
|
||||||
|
|
@ -65,9 +71,8 @@ public final class BeanMethod implements Validatable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the annotation on this method matching <var>annoType</var> or null
|
* @return the annotation on this method matching <var>annoType</var> or
|
||||||
* IllegalStateException} if not present.
|
* {@literal null} if not present.
|
||||||
*
|
|
||||||
* @see #getRequiredAnnotation(Class)
|
* @see #getRequiredAnnotation(Class)
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
|
@ -80,9 +85,8 @@ public final class BeanMethod implements Validatable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the annotation on this method matching <var>annoType</var> or throws
|
* @return the annotation on this method matching <var>annoType</var>
|
||||||
* {@link IllegalStateException} if not present.
|
* @throws {@link IllegalStateException} if not present
|
||||||
*
|
|
||||||
* @see #getAnnotation(Class)
|
* @see #getAnnotation(Class)
|
||||||
*/
|
*/
|
||||||
public <T extends Annotation> T getRequiredAnnotation(Class<T> annoType) {
|
public <T extends Annotation> T getRequiredAnnotation(Class<T> annoType) {
|
||||||
|
|
@ -96,7 +100,7 @@ public final class BeanMethod implements Validatable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets up bi-directional relationship between this method and its declaring class.
|
* Set up a bi-directional relationship between this method and its declaring class.
|
||||||
*
|
*
|
||||||
* @see ConfigurationClass#addMethod(BeanMethod)
|
* @see ConfigurationClass#addMethod(BeanMethod)
|
||||||
*/
|
*/
|
||||||
|
|
@ -116,22 +120,20 @@ public final class BeanMethod implements Validatable {
|
||||||
return lineNumber;
|
return lineNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void validate(List<UsageError> errors) {
|
public void validate(ProblemReporter problemReporter) {
|
||||||
|
|
||||||
if (Modifier.isPrivate(getModifiers()))
|
if (Modifier.isPrivate(getModifiers()))
|
||||||
errors.add(new PrivateMethodError());
|
problemReporter.error(new PrivateMethodError());
|
||||||
|
|
||||||
if (Modifier.isFinal(getModifiers()))
|
if (Modifier.isFinal(getModifiers()))
|
||||||
errors.add(new FinalMethodError());
|
problemReporter.error(new FinalMethodError());
|
||||||
|
|
||||||
if (this.getAnnotation(ScopedProxy.class) == null)
|
if (this.getAnnotation(ScopedProxy.class) == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Bean bean =this.getRequiredAnnotation(Bean.class);
|
Scope scope = this.getAnnotation(Scope.class);
|
||||||
|
if(scope == null || scope.equals(SINGLETON) || scope.equals(PROTOTYPE))
|
||||||
if (bean.scope().equals(StandardScopes.SINGLETON)
|
problemReporter.error(new InvalidScopedProxyDeclarationError(this));
|
||||||
|| bean.scope().equals(StandardScopes.PROTOTYPE))
|
|
||||||
errors.add(new InvalidScopedProxyDeclarationError(this));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -181,27 +183,17 @@ public final class BeanMethod implements Validatable {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** JavaConfigMethods must be visible (non-private) in order to accommodate CGLIB. */
|
/** {@link Bean} methods must be non-private in order to accommodate CGLIB. */
|
||||||
public class PrivateMethodError extends UsageError {
|
public class PrivateMethodError extends Problem {
|
||||||
public PrivateMethodError() {
|
public PrivateMethodError() {
|
||||||
super(getDeclaringClass(), getLineNumber());
|
super(format("method '%s' may not be private", getName()), new Location(new FileSystemResource("/dev/null")));
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getDescription() {
|
|
||||||
return format("method '%s' may not be private", getName());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** JavaConfigMethods must be extensible (non-final) in order to accommodate CGLIB. */
|
/** {@link Bean} methods must be non-final in order to accommodate CGLIB. */
|
||||||
public class FinalMethodError extends UsageError {
|
public class FinalMethodError extends Problem {
|
||||||
public FinalMethodError() {
|
public FinalMethodError() {
|
||||||
super(getDeclaringClass(), getLineNumber());
|
super(format("method '%s' may not be final. remove the final modifier to continue", getName()), new Location(new FileSystemResource("/dev/null")));
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getDescription() {
|
|
||||||
return format("method '%s' may not be final - remove the final modifier to continue", getName());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ import static java.lang.String.*;
|
||||||
import static org.springframework.util.StringUtils.*;
|
import static org.springframework.util.StringUtils.*;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
@ -15,6 +17,7 @@ import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||||
|
import org.springframework.context.annotation.Scope;
|
||||||
import org.springframework.core.annotation.AnnotationUtils;
|
import org.springframework.core.annotation.AnnotationUtils;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -43,19 +46,27 @@ public class BeanRegistrar implements BeanDefinitionRegistrar {
|
||||||
|
|
||||||
Bean bean = method.getRequiredAnnotation(Bean.class);
|
Bean bean = method.getRequiredAnnotation(Bean.class);
|
||||||
|
|
||||||
Configuration defaults = configClass.getMetadata();
|
// TODO: prune defaults
|
||||||
|
//Configuration defaults = configClass.getMetadata();
|
||||||
|
|
||||||
// consider scoping
|
// consider scoping
|
||||||
beanDef.setScope(bean.scope());
|
Scope scope = method.getAnnotation(Scope.class);
|
||||||
|
if(scope != null)
|
||||||
|
beanDef.setScope(scope.value());
|
||||||
|
|
||||||
// consider autowiring
|
// TODO: prune autowiring
|
||||||
if (bean.autowire() != AnnotationUtils.getDefaultValue(Bean.class, "autowire"))
|
// // consider autowiring
|
||||||
beanDef.setAutowireMode(bean.autowire().value());
|
// if (bean.autowire() != AnnotationUtils.getDefaultValue(Bean.class, "autowire"))
|
||||||
else if (defaults.defaultAutowire() != AnnotationUtils.getDefaultValue(Configuration.class,
|
// beanDef.setAutowireMode(bean.autowire().value());
|
||||||
"defaultAutowire"))
|
// else if (defaults.defaultAutowire() != AnnotationUtils.getDefaultValue(Configuration.class,
|
||||||
beanDef.setAutowireMode(defaults.defaultAutowire().value());
|
// "defaultAutowire"))
|
||||||
|
// beanDef.setAutowireMode(defaults.defaultAutowire().value());
|
||||||
|
|
||||||
String beanName = method.getName();
|
// consider name and any aliases
|
||||||
|
ArrayList<String> names = new ArrayList<String>(Arrays.asList(bean.name()));
|
||||||
|
String beanName = (names.size() > 0) ? names.remove(0) : method.getName();
|
||||||
|
for (String alias : bean.name())
|
||||||
|
registry.registerAlias(beanName, alias);
|
||||||
|
|
||||||
// has this already been overriden (i.e.: via XML)?
|
// has this already been overriden (i.e.: via XML)?
|
||||||
if (containsBeanDefinitionIncludingAncestry(beanName, registry)) {
|
if (containsBeanDefinitionIncludingAncestry(beanName, registry)) {
|
||||||
|
|
@ -65,11 +76,12 @@ public class BeanRegistrar implements BeanDefinitionRegistrar {
|
||||||
if (!(existingBeanDef instanceof ConfigurationClassBeanDefinition)) {
|
if (!(existingBeanDef instanceof ConfigurationClassBeanDefinition)) {
|
||||||
// no -> then it's an external override, probably XML
|
// no -> then it's an external override, probably XML
|
||||||
|
|
||||||
// ensure that overriding is ok
|
// TODO: Prune this
|
||||||
if (bean.allowOverriding() == false) {
|
// // ensure that overriding is ok
|
||||||
UsageError error = configClass.new IllegalBeanOverrideError(null, method);
|
// if (bean.allowOverriding() == false) {
|
||||||
throw new MalformedConfigurationException(error);
|
// UsageError error = configClass.new IllegalBeanOverrideError(null, method);
|
||||||
}
|
// throw new MalformedConfigurationException(error);
|
||||||
|
// }
|
||||||
|
|
||||||
// overriding is legal, return immediately
|
// overriding is legal, return immediately
|
||||||
logger.info(format("Skipping loading bean definition for %s: a definition for bean "
|
logger.info(format("Skipping loading bean definition for %s: a definition for bean "
|
||||||
|
|
@ -78,13 +90,6 @@ public class BeanRegistrar implements BeanDefinitionRegistrar {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
// TODO: re-enable for Lazy support
|
||||||
// // is this bean marked as primary for disambiguation?
|
// // is this bean marked as primary for disambiguation?
|
||||||
// if (bean.primary() == Primary.TRUE)
|
// if (bean.primary() == Primary.TRUE)
|
||||||
|
|
@ -96,12 +101,12 @@ public class BeanRegistrar implements BeanDefinitionRegistrar {
|
||||||
// beanDef.setLazyInit(true);
|
// beanDef.setLazyInit(true);
|
||||||
|
|
||||||
// does this bean have a custom init-method specified?
|
// does this bean have a custom init-method specified?
|
||||||
String initMethodName = bean.initMethodName();
|
String initMethodName = bean.initMethod();
|
||||||
if (hasText(initMethodName))
|
if (hasText(initMethodName))
|
||||||
beanDef.setInitMethodName(initMethodName);
|
beanDef.setInitMethodName(initMethodName);
|
||||||
|
|
||||||
// does this bean have a custom destroy-method specified?
|
// does this bean have a custom destroy-method specified?
|
||||||
String destroyMethodName = bean.destroyMethodName();
|
String destroyMethodName = bean.destroyMethod();
|
||||||
if (hasText(destroyMethodName))
|
if (hasText(destroyMethodName))
|
||||||
beanDef.setDestroyMethodName(destroyMethodName);
|
beanDef.setDestroyMethodName(destroyMethodName);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,6 @@ import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowire;
|
|
||||||
import org.springframework.beans.factory.annotation.Required;
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -44,9 +42,13 @@ import org.springframework.stereotype.Component;
|
||||||
* fact that this annotation is meta-annotated with {@link Component @Component}.
|
* fact that this annotation is meta-annotated with {@link Component @Component}.
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
|
* May be used in conjunction with {@link Lazy}
|
||||||
|
*
|
||||||
* @author Rod Johnson
|
* @author Rod Johnson
|
||||||
* @author Chris Beams
|
* @author Chris Beams
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
|
* @see Lazy
|
||||||
|
* @see Bean
|
||||||
*/
|
*/
|
||||||
@Component
|
@Component
|
||||||
@Target( { ElementType.TYPE })
|
@Target( { ElementType.TYPE })
|
||||||
|
|
@ -55,22 +57,25 @@ import org.springframework.stereotype.Component;
|
||||||
@Documented
|
@Documented
|
||||||
public @interface Configuration {
|
public @interface Configuration {
|
||||||
|
|
||||||
/**
|
// TODO: consider pruning @Configuration(name[])
|
||||||
* Configuration name. Allow different variants, such as test, production etc. Default
|
// /**
|
||||||
* will always match.
|
// * Configuration name. Allow different variants, such as test, production etc. Default
|
||||||
*
|
// * will always match.
|
||||||
* @return
|
// *
|
||||||
*/
|
// * @return
|
||||||
String[] names() default "";
|
// */
|
||||||
|
// String[] name() default "";
|
||||||
|
|
||||||
/**
|
// TODO: Prune defaultAutowire
|
||||||
* Specifies the default autowiring strategy.
|
// /**
|
||||||
*
|
// * Specifies the default autowiring strategy.
|
||||||
* @see Autowire
|
// *
|
||||||
* @return
|
// * @see Autowire
|
||||||
*/
|
// * @return
|
||||||
Autowire defaultAutowire() default Autowire.INHERITED;
|
// */
|
||||||
|
// Autowire defaultAutowire() default Autowire.INHERITED;
|
||||||
|
|
||||||
|
// TODO: Prune DependencyCheck
|
||||||
// /**
|
// /**
|
||||||
// * Dependency check strategy. By default, the dependency check is
|
// * Dependency check strategy. By default, the dependency check is
|
||||||
// * unspecified, that is the default Spring option will apply. In most cases,
|
// * unspecified, that is the default Spring option will apply. In most cases,
|
||||||
|
|
@ -81,6 +86,8 @@ public @interface Configuration {
|
||||||
// */
|
// */
|
||||||
// DependencyCheck defaultDependencyCheck() default DependencyCheck.UNSPECIFIED;
|
// DependencyCheck defaultDependencyCheck() default DependencyCheck.UNSPECIFIED;
|
||||||
//
|
//
|
||||||
|
|
||||||
|
// TODO: Favor @Lazy at the @Configuration class level. Should have @Target(TYPE, METHOD)
|
||||||
// /**
|
// /**
|
||||||
// * Bean instantiation strategy. By default, it is unspecified.
|
// * Bean instantiation strategy. By default, it is unspecified.
|
||||||
// *
|
// *
|
||||||
|
|
@ -89,14 +96,16 @@ public @interface Configuration {
|
||||||
// */
|
// */
|
||||||
// Lazy defaultLazy() default Lazy.UNSPECIFIED;
|
// Lazy defaultLazy() default Lazy.UNSPECIFIED;
|
||||||
|
|
||||||
/**
|
// TODO: prune useFactoryAspects
|
||||||
* Do we autowire with aspects from the enclosing factory scope?
|
// /**
|
||||||
*/
|
// * Do we autowire with aspects from the enclosing factory scope?
|
||||||
boolean useFactoryAspects() default false;
|
// */
|
||||||
|
// boolean useFactoryAspects() default false;
|
||||||
|
|
||||||
/**
|
// TODO: this is the default, and needs to be switched off at annotation-config
|
||||||
* Do we check {@link Required @Required} methods to make sure they've been called?
|
// /**
|
||||||
*/
|
// * Do we check {@link Required @Required} methods to make sure they've been called?
|
||||||
boolean checkRequired() default false;
|
// */
|
||||||
|
// boolean checkRequired() default false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,12 @@ import static java.lang.String.*;
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.parsing.Location;
|
||||||
|
import org.springframework.beans.factory.parsing.Problem;
|
||||||
|
import org.springframework.beans.factory.parsing.ProblemReporter;
|
||||||
|
import org.springframework.core.io.FileSystemResource;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
import sun.security.x509.Extension;
|
import sun.security.x509.Extension;
|
||||||
|
|
@ -47,7 +50,7 @@ import sun.security.x509.Extension;
|
||||||
*/
|
*/
|
||||||
// TODO: SJC-242 update documentation in light of generalization changes
|
// TODO: SJC-242 update documentation in light of generalization changes
|
||||||
// consider removing all refs to Bean, ExternalBean, etc.
|
// consider removing all refs to Bean, ExternalBean, etc.
|
||||||
public final class ConfigurationClass extends ModelClass implements Validatable {
|
public final class ConfigurationClass extends ModelClass {
|
||||||
|
|
||||||
private String beanName;
|
private String beanName;
|
||||||
|
|
||||||
|
|
@ -174,18 +177,18 @@ public final class ConfigurationClass extends ModelClass implements Validatable
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void validate(List<UsageError> errors) {
|
public void validate(ProblemReporter problemReporter) {
|
||||||
|
|
||||||
// configuration classes must be annotated with @Configuration
|
// configuration classes must be annotated with @Configuration
|
||||||
if (metadata == null)
|
if (metadata == null)
|
||||||
errors.add(new NonAnnotatedConfigurationError());
|
problemReporter.error(new NonAnnotatedConfigurationError());
|
||||||
|
|
||||||
// a configuration class may not be final (CGLIB limitation)
|
// a configuration class may not be final (CGLIB limitation)
|
||||||
if (Modifier.isFinal(modifiers))
|
if (Modifier.isFinal(modifiers))
|
||||||
errors.add(new FinalConfigurationError());
|
problemReporter.error(new FinalConfigurationError());
|
||||||
|
|
||||||
for (BeanMethod method : methods)
|
for (BeanMethod method : methods)
|
||||||
method.validate(errors);
|
method.validate(problemReporter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -248,94 +251,27 @@ public final class ConfigurationClass extends ModelClass implements Validatable
|
||||||
|
|
||||||
|
|
||||||
/** Configuration classes must be annotated with {@link Configuration @Configuration}. */
|
/** Configuration classes must be annotated with {@link Configuration @Configuration}. */
|
||||||
public class NonAnnotatedConfigurationError extends UsageError {
|
public class NonAnnotatedConfigurationError extends Problem {
|
||||||
public NonAnnotatedConfigurationError() {
|
public NonAnnotatedConfigurationError() {
|
||||||
super(ConfigurationClass.this, -1);
|
super(
|
||||||
|
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()),
|
||||||
|
new Location(new FileSystemResource("/dev/null"))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@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. */
|
/** Configuration classes must be non-final to accommodate CGLIB subclassing. */
|
||||||
public class FinalConfigurationError extends UsageError {
|
public class FinalConfigurationError extends Problem {
|
||||||
public FinalConfigurationError() {
|
public FinalConfigurationError() {
|
||||||
super(ConfigurationClass.this, -1);
|
super(
|
||||||
}
|
format("@%s class may not be final. Remove the final modifier to continue.",
|
||||||
|
Configuration.class.getSimpleName()),
|
||||||
@Override
|
new Location(new FileSystemResource("/dev/null"))
|
||||||
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 BeanMethod 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, BeanMethod 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 BeanMethod getMethod(String methodName) {
|
|
||||||
|
|
||||||
for (BeanMethod method : methods)
|
|
||||||
if (methodName.equals(method.getName()))
|
|
||||||
return method;
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,11 @@ package org.springframework.config.java;
|
||||||
import static java.lang.String.*;
|
import static java.lang.String.*;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
|
||||||
|
import org.springframework.beans.factory.parsing.Location;
|
||||||
|
import org.springframework.beans.factory.parsing.Problem;
|
||||||
|
import org.springframework.beans.factory.parsing.ProblemReporter;
|
||||||
|
import org.springframework.core.io.FileSystemResource;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -39,7 +43,7 @@ import java.util.List;
|
||||||
* @author Chris Beams
|
* @author Chris Beams
|
||||||
* @see org.springframework.config.java.internal.parsing.ConfigurationParser
|
* @see org.springframework.config.java.internal.parsing.ConfigurationParser
|
||||||
*/
|
*/
|
||||||
public final class ConfigurationModel implements Validatable {
|
public final class ConfigurationModel {
|
||||||
|
|
||||||
/* list is used because order and collection equality matters. */
|
/* list is used because order and collection equality matters. */
|
||||||
private final ArrayList<ConfigurationClass> configurationClasses = new ArrayList<ConfigurationClass>();
|
private final ArrayList<ConfigurationClass> configurationClasses = new ArrayList<ConfigurationClass>();
|
||||||
|
|
@ -89,35 +93,40 @@ public final class ConfigurationModel implements Validatable {
|
||||||
* Recurses through the model validating each object along the way and aggregating any
|
* Recurses through the model validating each object along the way and aggregating any
|
||||||
* <var>errors</var>.
|
* <var>errors</var>.
|
||||||
*
|
*
|
||||||
* @see ConfigurationClass#validate(java.util.List)
|
* @see ConfigurationClass#validate
|
||||||
* @see BeanMethod#validate(java.util.List)
|
* @see BeanMethod#validate
|
||||||
* @see UsageError
|
|
||||||
*/
|
*/
|
||||||
public void validate(List<UsageError> errors) {
|
public void validate(ProblemReporter problemReporter) {
|
||||||
// user must specify at least one configuration
|
// user must specify at least one configuration
|
||||||
if (configurationClasses.isEmpty())
|
if (configurationClasses.isEmpty())
|
||||||
errors.add(new EmptyModelError());
|
problemReporter.error(new EmptyModelError());
|
||||||
|
|
||||||
// check for any illegal @Bean overriding
|
// TODO: prune this
|
||||||
ConfigurationClass[] allClasses = getAllConfigurationClasses();
|
// // check for any illegal @Bean overriding
|
||||||
for (int i = 0; i < allClasses.length; i++) {
|
// ConfigurationClass[] allClasses = getAllConfigurationClasses();
|
||||||
for (BeanMethod method : allClasses[i].getMethods()) {
|
// for (int i = 0; i < allClasses.length; i++) {
|
||||||
Bean bean = method.getAnnotation(Bean.class);
|
// for (BeanMethod method : allClasses[i].getMethods()) {
|
||||||
|
// Bean bean = method.getAnnotation(Bean.class);
|
||||||
if (bean == null || bean.allowOverriding())
|
//
|
||||||
continue;
|
// if (bean == null || bean.allowOverriding())
|
||||||
|
// continue;
|
||||||
for (int j = i + 1; j < allClasses.length; j++)
|
//
|
||||||
if (allClasses[j].hasMethod(method.getName()))
|
// for (int j = i + 1; j < allClasses.length; j++)
|
||||||
errors.add(allClasses[i].new IllegalBeanOverrideError(allClasses[j], method));
|
// if (allClasses[j].hasMethod(method.getName()))
|
||||||
}
|
// problemReporter.error(
|
||||||
}
|
// new Problem(
|
||||||
|
// allClasses[i].new IllegalBeanOverrideError(allClasses[j], method).getDescription(),
|
||||||
|
// new Location(new ClassPathResource(allClasses[i].getName().replace('.', '/').concat(".class")))
|
||||||
|
// )
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
// each individual configuration class must be well-formed
|
// each individual configuration class must be well-formed
|
||||||
// note that each configClass detects usage errors on its imports recursively
|
// note that each configClass detects usage errors on its imports recursively
|
||||||
// note that each configClass will recursively process its respective methods
|
// note that each configClass will recursively process its respective methods
|
||||||
for (ConfigurationClass configClass : configurationClasses)
|
for (ConfigurationClass configClass : configurationClasses)
|
||||||
configClass.validate(errors);
|
configClass.validate(problemReporter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -151,15 +160,13 @@ public final class ConfigurationModel implements Validatable {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public class EmptyModelError extends UsageError {
|
public class EmptyModelError extends Problem {
|
||||||
public EmptyModelError() {
|
public EmptyModelError() {
|
||||||
super(null, 0);
|
super(
|
||||||
}
|
format("Configuration model was empty. Make sure at least one "
|
||||||
|
+ "@%s class has been specified.", Configuration.class.getSimpleName()),
|
||||||
@Override
|
new Location(new FileSystemResource("/dev/null"))
|
||||||
public String getDescription() {
|
);
|
||||||
return format("Configuration model was empty. Make sure at least one "
|
|
||||||
+ "@%s class has been specified.", Configuration.class.getSimpleName());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,19 +15,19 @@
|
||||||
*/
|
*/
|
||||||
package org.springframework.config.java;
|
package org.springframework.config.java;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.parsing.Location;
|
||||||
|
import org.springframework.beans.factory.parsing.Problem;
|
||||||
|
import org.springframework.core.io.FileSystemResource;
|
||||||
|
|
||||||
public class InvalidScopedProxyDeclarationError extends UsageError {
|
|
||||||
private final BeanMethod method;
|
|
||||||
|
|
||||||
|
public class InvalidScopedProxyDeclarationError extends Problem {
|
||||||
public InvalidScopedProxyDeclarationError(BeanMethod method) {
|
public InvalidScopedProxyDeclarationError(BeanMethod method) {
|
||||||
super(method.getDeclaringClass(), method.getLineNumber());
|
super(
|
||||||
this.method = method;
|
String.format("method %s contains an invalid annotation declaration: @%s "
|
||||||
|
+ "cannot be used on a singleton/prototype bean", method.getName(), ScopedProxy.class
|
||||||
|
.getSimpleName()),
|
||||||
|
new Location(new FileSystemResource("/dev/null"))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getDescription() {
|
|
||||||
return String.format("method %s contains an invalid annotation declaration: @%s "
|
|
||||||
+ "cannot be used on a singleton/prototype bean", method.getName(), ScopedProxy.class
|
|
||||||
.getSimpleName());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,75 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2008 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.springframework.config.java;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO: rename to UsageException / move outside .internal?
|
|
||||||
*
|
|
||||||
* @author Chris Beams
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("serial")
|
|
||||||
public class MalformedConfigurationException extends RuntimeException {
|
|
||||||
|
|
||||||
private final List<? extends UsageError> errors;
|
|
||||||
|
|
||||||
public MalformedConfigurationException(String message) {
|
|
||||||
super(message);
|
|
||||||
this.errors = new ArrayList<UsageError>();
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
sb.append("\n");
|
|
||||||
|
|
||||||
if (errors.length == 1)
|
|
||||||
sb.append("A usage error has ");
|
|
||||||
else
|
|
||||||
sb.append(errors.length + " usage errors have ");
|
|
||||||
|
|
||||||
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');
|
|
||||||
}
|
|
||||||
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,73 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2008 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.springframework.config.java;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delegates directly to {@link #getAttributedDescription()}.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return getAttributedDescription();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
package org.springframework.config.java;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates a type is able to be validated for errors.
|
|
||||||
*
|
|
||||||
* @author Chris Beams
|
|
||||||
*/
|
|
||||||
interface Validatable {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates this object, adding any errors to the supplied list of <var>errors</var>.
|
|
||||||
*/
|
|
||||||
public void validate(List<UsageError> errors);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -174,6 +174,7 @@ public class ConfigurationEnhancer {
|
||||||
* @return original subclass instance unless superclass is annnotated with @Aspect, in
|
* @return original subclass instance unless superclass is annnotated with @Aspect, in
|
||||||
* which case a subclass of the subclass is returned
|
* which case a subclass of the subclass is returned
|
||||||
*/
|
*/
|
||||||
|
// TODO: try to implement with modifications to AbstractAspectJAdvisorFactory#isAspect
|
||||||
private Class<?> nestOneClassDeeperIfAspect(Class<?> superclass, Class<?> origSubclass) {
|
private Class<?> nestOneClassDeeperIfAspect(Class<?> superclass, Class<?> origSubclass) {
|
||||||
boolean superclassIsAnAspect = false;
|
boolean superclassIsAnAspect = false;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,11 +16,13 @@
|
||||||
package org.springframework.config.java.support;
|
package org.springframework.config.java.support;
|
||||||
|
|
||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
|
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
|
||||||
|
import org.springframework.beans.factory.parsing.FailFastProblemReporter;
|
||||||
|
import org.springframework.beans.factory.parsing.ProblemReporter;
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||||
import org.springframework.config.java.Bean;
|
import org.springframework.config.java.Bean;
|
||||||
import org.springframework.config.java.Configuration;
|
import org.springframework.config.java.Configuration;
|
||||||
import org.springframework.config.java.ConfigurationModel;
|
import org.springframework.config.java.ConfigurationModel;
|
||||||
import org.springframework.config.java.MalformedConfigurationException;
|
|
||||||
import org.springframework.config.java.internal.parsing.ConfigurationParser;
|
import org.springframework.config.java.internal.parsing.ConfigurationParser;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -44,6 +46,14 @@ import org.springframework.config.java.internal.parsing.ConfigurationParser;
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractConfigurationClassProcessor {
|
public abstract class AbstractConfigurationClassProcessor {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to register any problems detected with {@link Configuration} or {@link Bean}
|
||||||
|
* declarations. For instance, a Bean method marked as {@literal final} is illegal
|
||||||
|
* and would be reported as a problem. Defaults to {@link FailFastProblemReporter},
|
||||||
|
* but is overridable with {@link #setProblemReporter}
|
||||||
|
*/
|
||||||
|
private ProblemReporter problemReporter = new FailFastProblemReporter();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Populate and return a registry containing all {@link Configuration} bean definitions
|
* Populate and return a registry containing all {@link Configuration} bean definitions
|
||||||
* to be processed.
|
* to be processed.
|
||||||
|
|
@ -65,12 +75,27 @@ public abstract class AbstractConfigurationClassProcessor {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate the given model and handle any errors. Implementations may choose to throw
|
* Validate the given model and handle any errors. Implementations may choose to throw
|
||||||
* {@link MalformedConfigurationException}, or in the case of tooling register problems
|
* {@link BeanDefinitionParsingException}, or in the case of tooling register problems
|
||||||
* with the UI.
|
* with the UI.
|
||||||
* @param configModel {@link ConfigurationModel} to validate
|
* @param configModel {@link ConfigurationModel} to validate
|
||||||
*/
|
*/
|
||||||
protected abstract void validateModel(ConfigurationModel configModel);
|
protected abstract void validateModel(ConfigurationModel configModel);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override the default {@link ProblemReporter}.
|
||||||
|
* @param problemReporter custom problem reporter
|
||||||
|
*/
|
||||||
|
protected final void setProblemReporter(ProblemReporter problemReporter) {
|
||||||
|
this.problemReporter = problemReporter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the currently registered {@link ProblemReporter}.
|
||||||
|
*/
|
||||||
|
protected final ProblemReporter getProblemReporter() {
|
||||||
|
return problemReporter;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build and validate a {@link ConfigurationModel} based on the registry of
|
* Build and validate a {@link ConfigurationModel} based on the registry of
|
||||||
* {@link Configuration} classes provided by {@link #getConfigurationBeanDefinitions},
|
* {@link Configuration} classes provided by {@link #getConfigurationBeanDefinitions},
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ package org.springframework.config.java.support;
|
||||||
import static java.lang.String.*;
|
import static java.lang.String.*;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
@ -31,8 +30,6 @@ import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||||
import org.springframework.config.java.Bean;
|
import org.springframework.config.java.Bean;
|
||||||
import org.springframework.config.java.Configuration;
|
import org.springframework.config.java.Configuration;
|
||||||
import org.springframework.config.java.ConfigurationModel;
|
import org.springframework.config.java.ConfigurationModel;
|
||||||
import org.springframework.config.java.MalformedConfigurationException;
|
|
||||||
import org.springframework.config.java.UsageError;
|
|
||||||
import org.springframework.config.java.internal.enhancement.ConfigurationEnhancer;
|
import org.springframework.config.java.internal.enhancement.ConfigurationEnhancer;
|
||||||
import org.springframework.config.java.internal.parsing.ConfigurationParser;
|
import org.springframework.config.java.internal.parsing.ConfigurationParser;
|
||||||
import org.springframework.core.Ordered;
|
import org.springframework.core.Ordered;
|
||||||
|
|
@ -136,15 +133,12 @@ public class ConfigurationClassPostProcessor extends AbstractConfigurationClassP
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates the given <var>model</var>.
|
* Validates the given <var>model</var>. Any problems found are delegated
|
||||||
* @throws MalformedConfigurationException if any errors are detected
|
* to {@link #getProblemReporter()}.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void validateModel(ConfigurationModel model) {
|
protected void validateModel(ConfigurationModel model) {
|
||||||
ArrayList<UsageError> errors = new ArrayList<UsageError>();
|
model.validate(this.getProblemReporter());
|
||||||
model.validate(errors);
|
|
||||||
if (errors.size() > 0)
|
|
||||||
throw new MalformedConfigurationException(errors.toArray(new UsageError[] {}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -19,12 +19,10 @@ import static java.lang.String.*;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor;
|
|
||||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionReader;
|
import org.springframework.beans.factory.support.BeanDefinitionReader;
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||||
import org.springframework.beans.factory.support.GenericBeanDefinition;
|
import org.springframework.beans.factory.support.GenericBeanDefinition;
|
||||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
|
||||||
import org.springframework.beans.factory.support.SimpleBeanDefinitionRegistry;
|
import org.springframework.beans.factory.support.SimpleBeanDefinitionRegistry;
|
||||||
import org.springframework.config.java.Bean;
|
import org.springframework.config.java.Bean;
|
||||||
import org.springframework.config.java.BeanMethod;
|
import org.springframework.config.java.BeanMethod;
|
||||||
|
|
@ -96,18 +94,18 @@ class ConfigurationModelBeanDefinitionReader {
|
||||||
* @param beanDefs
|
* @param beanDefs
|
||||||
*/
|
*/
|
||||||
private void doLoadBeanDefinitionForConfigurationClass(ConfigurationClass configClass) {
|
private void doLoadBeanDefinitionForConfigurationClass(ConfigurationClass configClass) {
|
||||||
Configuration metadata = configClass.getMetadata();
|
|
||||||
|
|
||||||
// TODO: think about implications with annotation-config
|
// TODO: prune support for @Required
|
||||||
if (metadata.checkRequired() == true) {
|
// Configuration metadata = configClass.getMetadata();
|
||||||
RootBeanDefinition requiredAnnotationPostProcessor = new RootBeanDefinition();
|
// if (metadata.checkRequired() == true) {
|
||||||
Class<?> beanClass = RequiredAnnotationBeanPostProcessor.class;
|
// RootBeanDefinition requiredAnnotationPostProcessor = new RootBeanDefinition();
|
||||||
String beanName = beanClass.getName() + "#0";
|
// Class<?> beanClass = RequiredAnnotationBeanPostProcessor.class;
|
||||||
requiredAnnotationPostProcessor.setBeanClass(beanClass);
|
// String beanName = beanClass.getName() + "#0";
|
||||||
requiredAnnotationPostProcessor
|
// requiredAnnotationPostProcessor.setBeanClass(beanClass);
|
||||||
.setResourceDescription("ensures @Required methods have been invoked");
|
// requiredAnnotationPostProcessor
|
||||||
registry.registerBeanDefinition(beanName, requiredAnnotationPostProcessor);
|
// .setResourceDescription("ensures @Required methods have been invoked");
|
||||||
}
|
// registry.registerBeanDefinition(beanName, requiredAnnotationPostProcessor);
|
||||||
|
// }
|
||||||
|
|
||||||
GenericBeanDefinition configBeanDef = new GenericBeanDefinition();
|
GenericBeanDefinition configBeanDef = new GenericBeanDefinition();
|
||||||
configBeanDef.setBeanClassName(configClass.getName());
|
configBeanDef.setBeanClassName(configClass.getName());
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,9 @@ import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||||
import org.springframework.config.java.Bean;
|
import org.springframework.config.java.Bean;
|
||||||
import org.springframework.config.java.Configuration;
|
import org.springframework.config.java.Configuration;
|
||||||
import org.springframework.config.java.MalformedConfigurationException;
|
|
||||||
import org.springframework.config.java.StandardScopes;
|
import org.springframework.config.java.StandardScopes;
|
||||||
import org.springframework.config.java.support.ConfigurationClassPostProcessor;
|
import org.springframework.config.java.support.ConfigurationClassPostProcessor;
|
||||||
|
import org.springframework.context.annotation.Scope;
|
||||||
|
|
||||||
import test.beans.ITestBean;
|
import test.beans.ITestBean;
|
||||||
import test.beans.TestBean;
|
import test.beans.TestBean;
|
||||||
|
|
@ -96,68 +96,10 @@ public class BasicTests {
|
||||||
return bar;
|
return bar;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean(scope = StandardScopes.PROTOTYPE)
|
@Bean @Scope(StandardScopes.PROTOTYPE)
|
||||||
public TestBean baz() {
|
public TestBean baz() {
|
||||||
return new TestBean("bar");
|
return new TestBean("bar");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void legalBeanOverriding() {
|
|
||||||
{
|
|
||||||
BeanFactory factory = initBeanFactory(ConfigWithBeanThatAllowsOverriding.class, ConfigWithBeanOverride.class);
|
|
||||||
|
|
||||||
TestBean testBean = factory.getBean("testBean", TestBean.class);
|
|
||||||
|
|
||||||
assertThat(testBean.getName(), equalTo("overridden"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// now try it the other way around - order matters!
|
|
||||||
|
|
||||||
{
|
|
||||||
BeanFactory factory = initBeanFactory(ConfigWithBeanOverride.class, ConfigWithBeanThatAllowsOverriding.class);
|
|
||||||
|
|
||||||
TestBean testBean = factory.getBean("testBean", TestBean.class);
|
|
||||||
|
|
||||||
assertThat(testBean.getName(), equalTo("original"));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected=MalformedConfigurationException.class)
|
|
||||||
public void illegalBeanOverriding() {
|
|
||||||
initBeanFactory(ConfigWithBeanThatDisallowsOverriding.class, ConfigWithBeanOverride.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void illegalBeanOverriding2() {
|
|
||||||
// should be okay when the class that disallows overriding is the one doing the overriding
|
|
||||||
initBeanFactory(ConfigWithBeanOverride.class, ConfigWithBeanThatDisallowsOverriding.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
static class ConfigWithBeanThatAllowsOverriding {
|
|
||||||
@Bean
|
|
||||||
public TestBean testBean() {
|
|
||||||
return new TestBean("original");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
static class ConfigWithBeanThatDisallowsOverriding {
|
|
||||||
@Bean(allowOverriding = false)
|
|
||||||
public TestBean testBean() {
|
|
||||||
return new TestBean("original");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
static class ConfigWithBeanOverride {
|
|
||||||
@Bean
|
|
||||||
public TestBean testBean() {
|
|
||||||
return new TestBean("overridden");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,11 +24,10 @@ import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.aop.scope.ScopedObject;
|
import org.springframework.aop.scope.ScopedObject;
|
||||||
import org.springframework.beans.factory.config.Scope;
|
import org.springframework.beans.factory.config.Scope;
|
||||||
|
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
|
||||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||||
import org.springframework.config.java.Bean;
|
import org.springframework.config.java.Bean;
|
||||||
import org.springframework.config.java.Configuration;
|
import org.springframework.config.java.Configuration;
|
||||||
import org.springframework.config.java.InvalidScopedProxyDeclarationError;
|
|
||||||
import org.springframework.config.java.MalformedConfigurationException;
|
|
||||||
import org.springframework.config.java.ScopedProxy;
|
import org.springframework.config.java.ScopedProxy;
|
||||||
import org.springframework.config.java.StandardScopes;
|
import org.springframework.config.java.StandardScopes;
|
||||||
import org.springframework.config.java.support.ConfigurationClassPostProcessor;
|
import org.springframework.config.java.support.ConfigurationClassPostProcessor;
|
||||||
|
|
@ -118,8 +117,8 @@ public class ScopingTests {
|
||||||
try {
|
try {
|
||||||
createContext(null, InvalidProxyOnPredefinedScopesConfiguration.class);
|
createContext(null, InvalidProxyOnPredefinedScopesConfiguration.class);
|
||||||
fail("exception expected");
|
fail("exception expected");
|
||||||
} catch (MalformedConfigurationException ex) {
|
} catch (BeanDefinitionParsingException ex) {
|
||||||
assertTrue(ex.containsError(InvalidScopedProxyDeclarationError.class));
|
assertTrue(ex.getMessage().contains("cannot be used on a singleton/prototype bean"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -241,7 +240,8 @@ public class ScopingTests {
|
||||||
@Configuration
|
@Configuration
|
||||||
static class ScopeTestConfiguration {
|
static class ScopeTestConfiguration {
|
||||||
|
|
||||||
@Bean(scope = StandardScopes.SESSION)
|
@Bean
|
||||||
|
@org.springframework.context.annotation.Scope(StandardScopes.SESSION)
|
||||||
@ScopedProxy
|
@ScopedProxy
|
||||||
public Foo foo() {
|
public Foo foo() {
|
||||||
return new Foo();
|
return new Foo();
|
||||||
|
|
@ -326,21 +326,24 @@ public class ScopingTests {
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
public static class ScopedConfigurationClass {
|
public static class ScopedConfigurationClass {
|
||||||
@Bean(scope = SCOPE)
|
@Bean
|
||||||
|
@org.springframework.context.annotation.Scope(SCOPE)
|
||||||
public TestBean scopedClass() {
|
public TestBean scopedClass() {
|
||||||
TestBean tb = new TestBean();
|
TestBean tb = new TestBean();
|
||||||
tb.setName(flag);
|
tb.setName(flag);
|
||||||
return tb;
|
return tb;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean(scope = SCOPE)
|
@Bean
|
||||||
|
@org.springframework.context.annotation.Scope(SCOPE)
|
||||||
public ITestBean scopedInterface() {
|
public ITestBean scopedInterface() {
|
||||||
TestBean tb = new TestBean();
|
TestBean tb = new TestBean();
|
||||||
tb.setName(flag);
|
tb.setName(flag);
|
||||||
return tb;
|
return tb;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean(scope = SCOPE)
|
@Bean
|
||||||
|
@org.springframework.context.annotation.Scope(SCOPE)
|
||||||
@ScopedProxy(proxyTargetClass = false)
|
@ScopedProxy(proxyTargetClass = false)
|
||||||
public ITestBean scopedProxyInterface() {
|
public ITestBean scopedProxyInterface() {
|
||||||
TestBean tb = new TestBean();
|
TestBean tb = new TestBean();
|
||||||
|
|
@ -349,7 +352,8 @@ public class ScopingTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ScopedProxy
|
@ScopedProxy
|
||||||
@Bean(scope = SCOPE)
|
@Bean
|
||||||
|
@org.springframework.context.annotation.Scope(SCOPE)
|
||||||
public TestBean scopedProxyClass() {
|
public TestBean scopedProxyClass() {
|
||||||
TestBean tb = new TestBean();
|
TestBean tb = new TestBean();
|
||||||
tb.setName(flag);
|
tb.setName(flag);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue