Remove "Feature" support introduced in 3.1 M1
Feature-related support such as @Feature, @FeatureConfiguration, and FeatureSpecification types will be replaced by framework-provided @Configuration classes and convenience annotations such as @ComponentScan (already exists), @EnableAsync, @EnableScheduling, @EnableTransactionManagement and others. Issue: SPR-8012,SPR-8034,SPR-8039,SPR-8188,SPR-8206,SPR-8223, SPR-8225,SPR-8226,SPR-8227
This commit is contained in:
@@ -16,13 +16,13 @@
|
||||
|
||||
package org.springframework.context.annotation;
|
||||
|
||||
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.type.MethodMetadata;
|
||||
|
||||
/**
|
||||
* Represents a {@link Configuration} class method marked with the {@link Bean} annotation.
|
||||
* Represents a {@link Configuration} class method marked with the
|
||||
* {@link Bean} annotation.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
@@ -31,30 +31,13 @@ import org.springframework.core.type.MethodMetadata;
|
||||
* @see ConfigurationClassParser
|
||||
* @see ConfigurationClassBeanDefinitionReader
|
||||
*/
|
||||
final class BeanMethod {
|
||||
|
||||
private final MethodMetadata metadata;
|
||||
|
||||
private final ConfigurationClass configurationClass;
|
||||
|
||||
final class BeanMethod extends ConfigurationMethod {
|
||||
|
||||
public BeanMethod(MethodMetadata metadata, ConfigurationClass configurationClass) {
|
||||
this.metadata = metadata;
|
||||
this.configurationClass = configurationClass;
|
||||
}
|
||||
|
||||
public MethodMetadata getMetadata() {
|
||||
return this.metadata;
|
||||
}
|
||||
|
||||
public ConfigurationClass getConfigurationClass() {
|
||||
return this.configurationClass;
|
||||
}
|
||||
|
||||
public Location getResourceLocation() {
|
||||
return new Location(this.configurationClass.getResource(), this.metadata);
|
||||
super(metadata, configurationClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(ProblemReporter problemReporter) {
|
||||
if (this.configurationClass.getMetadata().isAnnotated(Configuration.class.getName())) {
|
||||
if (!getMetadata().isOverridable()) {
|
||||
@@ -68,13 +51,6 @@ final class BeanMethod {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("[%s:name=%s,declaringClass=%s]",
|
||||
this.getClass().getSimpleName(), this.getMetadata().getMethodName(), this.getMetadata().getDeclaringClassName());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@link Bean} methods must be overridable in order to accommodate CGLIB.
|
||||
*/
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.context.annotation;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.context.annotation.ComponentScan.Filter;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* {@link FeatureAnnotationParser} implementation that reads attributes from a
|
||||
* {@link ComponentScan @ComponentScan} annotation into a {@link ComponentScanSpec}
|
||||
* which can in turn be executed by {@link ComponentScanExecutor}.
|
||||
* {@link ComponentScanBeanDefinitionParser} serves the same role for
|
||||
* the {@code <context:component-scan>} XML element.
|
||||
*
|
||||
* <p>Note that {@link ComponentScanSpec} objects may be directly
|
||||
* instantiated and returned from {@link Feature @Feature} methods as an
|
||||
* alternative to using the {@link ComponentScan @ComponentScan} annotation.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
* @see ComponentScan
|
||||
* @see ComponentScanSpec
|
||||
* @see ComponentScanExecutor
|
||||
* @see ComponentScanBeanDefinitionParser
|
||||
* @see ConfigurationClassBeanDefinitionReader
|
||||
*/
|
||||
final class ComponentScanAnnotationParser implements FeatureAnnotationParser {
|
||||
|
||||
/**
|
||||
* Create and return a new {@link ComponentScanSpec} from the given
|
||||
* {@link ComponentScan} annotation metadata.
|
||||
* @throws IllegalArgumentException if ComponentScan attributes are not present in metadata
|
||||
*/
|
||||
public ComponentScanSpec process(AnnotationMetadata metadata) {
|
||||
Map<String, Object> attribs = metadata.getAnnotationAttributes(ComponentScan.class.getName(), true);
|
||||
Assert.notNull(attribs, String.format("@ComponentScan annotation not found " +
|
||||
"while parsing metadata for class [%s].", metadata.getClassName()));
|
||||
|
||||
ClassLoader classLoader = ClassUtils.getDefaultClassLoader();
|
||||
ComponentScanSpec spec = new ComponentScanSpec();
|
||||
|
||||
for (String pkg : (String[])attribs.get("value")) {
|
||||
spec.addBasePackage(pkg);
|
||||
}
|
||||
for (String pkg : (String[])attribs.get("basePackages")) {
|
||||
spec.addBasePackage(pkg);
|
||||
}
|
||||
for (String className : (String[])attribs.get("basePackageClasses")) {
|
||||
spec.addBasePackage(className.substring(0, className.lastIndexOf('.')));
|
||||
}
|
||||
|
||||
String resolverAttribute = "scopeResolver";
|
||||
if (!((String)attribs.get(resolverAttribute)).equals(((Class<?>)AnnotationUtils.getDefaultValue(ComponentScan.class, resolverAttribute)).getName())) {
|
||||
spec.scopeMetadataResolver((String)attribs.get(resolverAttribute), classLoader);
|
||||
}
|
||||
String scopedProxyAttribute = "scopedProxy";
|
||||
ScopedProxyMode scopedProxyMode = (ScopedProxyMode) attribs.get(scopedProxyAttribute);
|
||||
if (scopedProxyMode != ((ScopedProxyMode)AnnotationUtils.getDefaultValue(ComponentScan.class, scopedProxyAttribute))) {
|
||||
spec.scopedProxyMode(scopedProxyMode);
|
||||
}
|
||||
|
||||
for (Filter filter : (Filter[]) attribs.get("includeFilters")) {
|
||||
spec.addIncludeFilter(filter.type().toString(), filter.value().getName(), classLoader);
|
||||
}
|
||||
for (Filter filter : (Filter[]) attribs.get("excludeFilters")) {
|
||||
spec.addExcludeFilter(filter.type().toString(), filter.value().getName(), classLoader);
|
||||
}
|
||||
|
||||
spec.resourcePattern((String)attribs.get("resourcePattern"))
|
||||
.useDefaultFilters((Boolean)attribs.get("useDefaultFilters"))
|
||||
.beanNameGenerator((String)attribs.get("nameGenerator"), classLoader)
|
||||
.source(metadata.getClassName())
|
||||
.sourceName(metadata.getClassName());
|
||||
|
||||
return spec;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,60 +16,263 @@
|
||||
|
||||
package org.springframework.context.annotation;
|
||||
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.context.config.AbstractSpecificationBeanDefinitionParser;
|
||||
import org.springframework.context.config.FeatureSpecification;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.FatalBeanException;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
|
||||
import org.springframework.beans.factory.support.BeanNameGenerator;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.beans.factory.xml.XmlReaderContext;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.type.filter.AnnotationTypeFilter;
|
||||
import org.springframework.core.type.filter.AspectJTypeFilter;
|
||||
import org.springframework.core.type.filter.AssignableTypeFilter;
|
||||
import org.springframework.core.type.filter.RegexPatternTypeFilter;
|
||||
import org.springframework.core.type.filter.TypeFilter;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Parser for the {@code <context:component-scan/>} element. Parsed metadata is
|
||||
* used to populate and execute a {@link ComponentScanSpec} instance.
|
||||
* Parser for the {@code <context:component-scan/>} element.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @author Ramnivas Laddad
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
* @since 2.5
|
||||
* @see ComponentScan
|
||||
* @see ComponentScanSpec
|
||||
* @see ComponentScanExecutor
|
||||
*/
|
||||
public class ComponentScanBeanDefinitionParser extends AbstractSpecificationBeanDefinitionParser {
|
||||
public class ComponentScanBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
public FeatureSpecification doParse(Element element, ParserContext parserContext) {
|
||||
ClassLoader classLoader = parserContext.getReaderContext().getResourceLoader().getClassLoader();
|
||||
private static final String BASE_PACKAGE_ATTRIBUTE = "base-package";
|
||||
|
||||
ComponentScanSpec spec =
|
||||
ComponentScanSpec.forDelimitedPackages(element.getAttribute("base-package"))
|
||||
.includeAnnotationConfig(element.getAttribute("annotation-config"))
|
||||
.useDefaultFilters(element.getAttribute("use-default-filters"))
|
||||
.resourcePattern(element.getAttribute("resource-pattern"))
|
||||
.beanNameGenerator(element.getAttribute("name-generator"), classLoader)
|
||||
.scopeMetadataResolver(element.getAttribute("scope-resolver"), classLoader)
|
||||
.scopedProxyMode(element.getAttribute("scoped-proxy"))
|
||||
.beanDefinitionDefaults(parserContext.getDelegate().getBeanDefinitionDefaults())
|
||||
.autowireCandidatePatterns(parserContext.getDelegate().getAutowireCandidatePatterns());
|
||||
private static final String RESOURCE_PATTERN_ATTRIBUTE = "resource-pattern";
|
||||
|
||||
private static final String USE_DEFAULT_FILTERS_ATTRIBUTE = "use-default-filters";
|
||||
|
||||
private static final String ANNOTATION_CONFIG_ATTRIBUTE = "annotation-config";
|
||||
|
||||
private static final String NAME_GENERATOR_ATTRIBUTE = "name-generator";
|
||||
|
||||
private static final String SCOPE_RESOLVER_ATTRIBUTE = "scope-resolver";
|
||||
|
||||
private static final String SCOPED_PROXY_ATTRIBUTE = "scoped-proxy";
|
||||
|
||||
private static final String EXCLUDE_FILTER_ELEMENT = "exclude-filter";
|
||||
|
||||
private static final String INCLUDE_FILTER_ELEMENT = "include-filter";
|
||||
|
||||
private static final String FILTER_TYPE_ATTRIBUTE = "type";
|
||||
|
||||
private static final String FILTER_EXPRESSION_ATTRIBUTE = "expression";
|
||||
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
String[] basePackages = StringUtils.tokenizeToStringArray(element.getAttribute(BASE_PACKAGE_ATTRIBUTE),
|
||||
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
|
||||
|
||||
// Actually scan for bean definitions and register them.
|
||||
ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
|
||||
Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
|
||||
registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected ClassPathBeanDefinitionScanner configureScanner(ParserContext parserContext, Element element) {
|
||||
XmlReaderContext readerContext = parserContext.getReaderContext();
|
||||
|
||||
boolean useDefaultFilters = true;
|
||||
if (element.hasAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE)) {
|
||||
useDefaultFilters = Boolean.valueOf(element.getAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE));
|
||||
}
|
||||
|
||||
// Delegate bean definition registration to scanner class.
|
||||
ClassPathBeanDefinitionScanner scanner = createScanner(readerContext, useDefaultFilters);
|
||||
scanner.setResourceLoader(readerContext.getResourceLoader());
|
||||
scanner.setBeanDefinitionDefaults(parserContext.getDelegate().getBeanDefinitionDefaults());
|
||||
scanner.setAutowireCandidatePatterns(parserContext.getDelegate().getAutowireCandidatePatterns());
|
||||
|
||||
if (element.hasAttribute(RESOURCE_PATTERN_ATTRIBUTE)) {
|
||||
scanner.setResourcePattern(element.getAttribute(RESOURCE_PATTERN_ATTRIBUTE));
|
||||
}
|
||||
|
||||
try {
|
||||
parseBeanNameGenerator(element, scanner);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
readerContext.error(ex.getMessage(), readerContext.extractSource(element), ex.getCause());
|
||||
}
|
||||
|
||||
try {
|
||||
parseScope(element, scanner);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
readerContext.error(ex.getMessage(), readerContext.extractSource(element), ex.getCause());
|
||||
}
|
||||
|
||||
parseTypeFilters(element, scanner, readerContext, parserContext);
|
||||
|
||||
return scanner;
|
||||
}
|
||||
|
||||
protected ClassPathBeanDefinitionScanner createScanner(XmlReaderContext readerContext, boolean useDefaultFilters) {
|
||||
return new ClassPathBeanDefinitionScanner(readerContext.getRegistry(), useDefaultFilters);
|
||||
}
|
||||
|
||||
protected void registerComponents(
|
||||
XmlReaderContext readerContext, Set<BeanDefinitionHolder> beanDefinitions, Element element) {
|
||||
|
||||
Object source = readerContext.extractSource(element);
|
||||
CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), source);
|
||||
|
||||
for (BeanDefinitionHolder beanDefHolder : beanDefinitions) {
|
||||
compositeDef.addNestedComponent(new BeanComponentDefinition(beanDefHolder));
|
||||
}
|
||||
|
||||
// Register annotation config processors, if necessary.
|
||||
boolean annotationConfig = true;
|
||||
if (element.hasAttribute(ANNOTATION_CONFIG_ATTRIBUTE)) {
|
||||
annotationConfig = Boolean.valueOf(element.getAttribute(ANNOTATION_CONFIG_ATTRIBUTE));
|
||||
}
|
||||
if (annotationConfig) {
|
||||
Set<BeanDefinitionHolder> processorDefinitions =
|
||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source);
|
||||
for (BeanDefinitionHolder processorDefinition : processorDefinitions) {
|
||||
compositeDef.addNestedComponent(new BeanComponentDefinition(processorDefinition));
|
||||
}
|
||||
}
|
||||
|
||||
readerContext.fireComponentRegistered(compositeDef);
|
||||
}
|
||||
|
||||
protected void parseBeanNameGenerator(Element element, ClassPathBeanDefinitionScanner scanner) {
|
||||
if (element.hasAttribute(NAME_GENERATOR_ATTRIBUTE)) {
|
||||
BeanNameGenerator beanNameGenerator = (BeanNameGenerator) instantiateUserDefinedStrategy(
|
||||
element.getAttribute(NAME_GENERATOR_ATTRIBUTE), BeanNameGenerator.class,
|
||||
scanner.getResourceLoader().getClassLoader());
|
||||
scanner.setBeanNameGenerator(beanNameGenerator);
|
||||
}
|
||||
}
|
||||
|
||||
protected void parseScope(Element element, ClassPathBeanDefinitionScanner scanner) {
|
||||
// Register ScopeMetadataResolver if class name provided.
|
||||
if (element.hasAttribute(SCOPE_RESOLVER_ATTRIBUTE)) {
|
||||
if (element.hasAttribute(SCOPED_PROXY_ATTRIBUTE)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot define both 'scope-resolver' and 'scoped-proxy' on <component-scan> tag");
|
||||
}
|
||||
ScopeMetadataResolver scopeMetadataResolver = (ScopeMetadataResolver) instantiateUserDefinedStrategy(
|
||||
element.getAttribute(SCOPE_RESOLVER_ATTRIBUTE), ScopeMetadataResolver.class,
|
||||
scanner.getResourceLoader().getClassLoader());
|
||||
scanner.setScopeMetadataResolver(scopeMetadataResolver);
|
||||
}
|
||||
|
||||
if (element.hasAttribute(SCOPED_PROXY_ATTRIBUTE)) {
|
||||
String mode = element.getAttribute(SCOPED_PROXY_ATTRIBUTE);
|
||||
if ("targetClass".equals(mode)) {
|
||||
scanner.setScopedProxyMode(ScopedProxyMode.TARGET_CLASS);
|
||||
}
|
||||
else if ("interfaces".equals(mode)) {
|
||||
scanner.setScopedProxyMode(ScopedProxyMode.INTERFACES);
|
||||
}
|
||||
else if ("no".equals(mode)) {
|
||||
scanner.setScopedProxyMode(ScopedProxyMode.NO);
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("scoped-proxy only supports 'no', 'interfaces' and 'targetClass'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void parseTypeFilters(
|
||||
Element element, ClassPathBeanDefinitionScanner scanner, XmlReaderContext readerContext, ParserContext parserContext) {
|
||||
|
||||
// Parse exclude and include filter elements.
|
||||
ClassLoader classLoader = scanner.getResourceLoader().getClassLoader();
|
||||
NodeList nodeList = element.getChildNodes();
|
||||
for (int i = 0; i < nodeList.getLength(); i++) {
|
||||
Node node = nodeList.item(i);
|
||||
if (node.getNodeType() == Node.ELEMENT_NODE) {
|
||||
String localName = parserContext.getDelegate().getLocalName(node);
|
||||
String filterType = ((Element)node).getAttribute("type");
|
||||
String expression = ((Element)node).getAttribute("expression");
|
||||
if ("include-filter".equals(localName)) {
|
||||
spec.addIncludeFilter(filterType, expression, classLoader);
|
||||
try {
|
||||
if (INCLUDE_FILTER_ELEMENT.equals(localName)) {
|
||||
TypeFilter typeFilter = createTypeFilter((Element) node, classLoader);
|
||||
scanner.addIncludeFilter(typeFilter);
|
||||
}
|
||||
else if (EXCLUDE_FILTER_ELEMENT.equals(localName)) {
|
||||
TypeFilter typeFilter = createTypeFilter((Element) node, classLoader);
|
||||
scanner.addExcludeFilter(typeFilter);
|
||||
}
|
||||
}
|
||||
else if ("exclude-filter".equals(localName)) {
|
||||
spec.addExcludeFilter(filterType, expression, classLoader);
|
||||
catch (Exception ex) {
|
||||
readerContext.error(ex.getMessage(), readerContext.extractSource(element), ex.getCause());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return spec;
|
||||
@SuppressWarnings("unchecked")
|
||||
protected TypeFilter createTypeFilter(Element element, ClassLoader classLoader) {
|
||||
String filterType = element.getAttribute(FILTER_TYPE_ATTRIBUTE);
|
||||
String expression = element.getAttribute(FILTER_EXPRESSION_ATTRIBUTE);
|
||||
try {
|
||||
if ("annotation".equals(filterType)) {
|
||||
return new AnnotationTypeFilter((Class<Annotation>) classLoader.loadClass(expression));
|
||||
}
|
||||
else if ("assignable".equals(filterType)) {
|
||||
return new AssignableTypeFilter(classLoader.loadClass(expression));
|
||||
}
|
||||
else if ("aspectj".equals(filterType)) {
|
||||
return new AspectJTypeFilter(expression, classLoader);
|
||||
}
|
||||
else if ("regex".equals(filterType)) {
|
||||
return new RegexPatternTypeFilter(Pattern.compile(expression));
|
||||
}
|
||||
else if ("custom".equals(filterType)) {
|
||||
Class filterClass = classLoader.loadClass(expression);
|
||||
if (!TypeFilter.class.isAssignableFrom(filterClass)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Class is not assignable to [" + TypeFilter.class.getName() + "]: " + expression);
|
||||
}
|
||||
return (TypeFilter) BeanUtils.instantiateClass(filterClass);
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Unsupported filter type: " + filterType);
|
||||
}
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
throw new FatalBeanException("Type filter class not found: " + expression, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Object instantiateUserDefinedStrategy(String className, Class strategyType, ClassLoader classLoader) {
|
||||
Object result = null;
|
||||
try {
|
||||
result = classLoader.loadClass(className).newInstance();
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
throw new IllegalArgumentException("Class [" + className + "] for strategy [" +
|
||||
strategyType.getName() + "] not found", ex);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalArgumentException("Unable to instantiate class [" + className + "] for strategy [" +
|
||||
strategyType.getName() + "]. A zero-argument constructor is required", ex);
|
||||
}
|
||||
|
||||
if (!strategyType.isAssignableFrom(result.getClass())) {
|
||||
throw new IllegalArgumentException("Provided class name must be an implementation of " + strategyType);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.context.annotation;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.context.config.AbstractSpecificationExecutor;
|
||||
import org.springframework.context.config.SpecificationContext;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.type.filter.TypeFilter;
|
||||
|
||||
/**
|
||||
* Executes the {@link ComponentScanSpec} feature specification.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
* @see ComponentScanSpec
|
||||
* @see ComponentScanBeanDefinitionParser
|
||||
* @see ComponentScan
|
||||
*/
|
||||
final class ComponentScanExecutor extends AbstractSpecificationExecutor<ComponentScanSpec> {
|
||||
|
||||
/**
|
||||
* Configure a {@link ClassPathBeanDefinitionScanner} based on the content of
|
||||
* the given specification and perform actual scanning and bean definition
|
||||
* registration.
|
||||
*/
|
||||
protected void doExecute(ComponentScanSpec spec, SpecificationContext specificationContext) {
|
||||
BeanDefinitionRegistry registry = specificationContext.getRegistry();
|
||||
ResourceLoader resourceLoader = specificationContext.getResourceLoader();
|
||||
Environment environment = specificationContext.getEnvironment();
|
||||
|
||||
ClassPathBeanDefinitionScanner scanner = spec.useDefaultFilters() == null ?
|
||||
new ClassPathBeanDefinitionScanner(registry) :
|
||||
new ClassPathBeanDefinitionScanner(registry, spec.useDefaultFilters());
|
||||
|
||||
scanner.setResourceLoader(resourceLoader);
|
||||
scanner.setEnvironment(environment);
|
||||
|
||||
if (spec.beanDefinitionDefaults() != null) {
|
||||
scanner.setBeanDefinitionDefaults(spec.beanDefinitionDefaults());
|
||||
}
|
||||
if (spec.autowireCandidatePatterns() != null) {
|
||||
scanner.setAutowireCandidatePatterns(spec.autowireCandidatePatterns());
|
||||
}
|
||||
|
||||
if (spec.resourcePattern() != null) {
|
||||
scanner.setResourcePattern(spec.resourcePattern());
|
||||
}
|
||||
if (spec.beanNameGenerator() != null) {
|
||||
scanner.setBeanNameGenerator(spec.beanNameGenerator());
|
||||
}
|
||||
if (spec.includeAnnotationConfig() != null) {
|
||||
scanner.setIncludeAnnotationConfig(spec.includeAnnotationConfig());
|
||||
}
|
||||
if (spec.scopeMetadataResolver() != null) {
|
||||
scanner.setScopeMetadataResolver(spec.scopeMetadataResolver());
|
||||
}
|
||||
if (spec.scopedProxyMode() != null) {
|
||||
scanner.setScopedProxyMode(spec.scopedProxyMode());
|
||||
}
|
||||
for (TypeFilter filter : spec.includeFilters()) {
|
||||
scanner.addIncludeFilter(filter);
|
||||
}
|
||||
for (TypeFilter filter : spec.excludeFilters()) {
|
||||
scanner.addExcludeFilter(filter);
|
||||
}
|
||||
|
||||
Set<BeanDefinitionHolder> scannedBeans = scanner.doScan(spec.basePackages());
|
||||
|
||||
Object source = spec.source();
|
||||
String sourceName = spec.sourceName();
|
||||
CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(sourceName, source);
|
||||
|
||||
for (BeanDefinitionHolder beanDefHolder : scannedBeans) {
|
||||
compositeDef.addNestedComponent(new BeanComponentDefinition(beanDefHolder));
|
||||
}
|
||||
|
||||
// Register annotation config processors, if necessary.
|
||||
if ((spec.includeAnnotationConfig() != null) && spec.includeAnnotationConfig()) {
|
||||
Set<BeanDefinitionHolder> processorDefinitions =
|
||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(registry, source);
|
||||
for (BeanDefinitionHolder processorDefinition : processorDefinitions) {
|
||||
compositeDef.addNestedComponent(new BeanComponentDefinition(processorDefinition));
|
||||
}
|
||||
}
|
||||
|
||||
specificationContext.getRegistrar().registerComponent(compositeDef);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,460 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.context.annotation;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.parsing.ProblemCollector;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionDefaults;
|
||||
import org.springframework.beans.factory.support.BeanNameGenerator;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.config.AbstractFeatureSpecification;
|
||||
import org.springframework.context.config.FeatureSpecificationExecutor;
|
||||
import org.springframework.core.type.classreading.MetadataReader;
|
||||
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||
import org.springframework.core.type.filter.AnnotationTypeFilter;
|
||||
import org.springframework.core.type.filter.AspectJTypeFilter;
|
||||
import org.springframework.core.type.filter.AssignableTypeFilter;
|
||||
import org.springframework.core.type.filter.RegexPatternTypeFilter;
|
||||
import org.springframework.core.type.filter.TypeFilter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Specifies the configuration of Spring's <em>component-scanning</em> feature.
|
||||
* May be used directly within a {@link Feature @Feature} method, or indirectly
|
||||
* through the {@link ComponentScan @ComponentScan} annotation.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
* @see ComponentScan
|
||||
* @see ComponentScanAnnotationParser
|
||||
* @see ComponentScanBeanDefinitionParser
|
||||
* @see ComponentScanExecutor
|
||||
*/
|
||||
public final class ComponentScanSpec extends AbstractFeatureSpecification {
|
||||
|
||||
private static final Class<? extends FeatureSpecificationExecutor> EXECUTOR_TYPE = ComponentScanExecutor.class;
|
||||
|
||||
private Boolean includeAnnotationConfig = null;
|
||||
private String resourcePattern = null;
|
||||
private List<String> basePackages = new ArrayList<String>();
|
||||
private Object beanNameGenerator = null;
|
||||
private Object scopeMetadataResolver = null;
|
||||
private Object scopedProxyMode = null;
|
||||
private Boolean useDefaultFilters = null;
|
||||
private List<Object> includeFilters = new ArrayList<Object>();
|
||||
private List<Object> excludeFilters = new ArrayList<Object>();
|
||||
|
||||
private BeanDefinitionDefaults beanDefinitionDefaults;
|
||||
private String[] autowireCandidatePatterns;
|
||||
|
||||
private ClassLoader classLoader;
|
||||
|
||||
/**
|
||||
* Package-visible constructor for use by {@link ComponentScanBeanDefinitionParser}.
|
||||
* End users should always call String... or Class<?>... constructors to specify
|
||||
* base packages.
|
||||
*
|
||||
* @see #validate()
|
||||
*/
|
||||
ComponentScanSpec() {
|
||||
super(EXECUTOR_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param basePackages
|
||||
* @see #forDelimitedPackages(String)
|
||||
*/
|
||||
public ComponentScanSpec(String... basePackages) {
|
||||
this();
|
||||
Assert.notEmpty(basePackages, "At least one base package must be specified");
|
||||
for (String basePackage : basePackages) {
|
||||
addBasePackage(basePackage);
|
||||
}
|
||||
}
|
||||
|
||||
public ComponentScanSpec(Class<?>... basePackageClasses) {
|
||||
this(packagesFor(basePackageClasses));
|
||||
}
|
||||
|
||||
|
||||
public ComponentScanSpec includeAnnotationConfig(Boolean includeAnnotationConfig) {
|
||||
this.includeAnnotationConfig = includeAnnotationConfig;
|
||||
return this;
|
||||
}
|
||||
|
||||
ComponentScanSpec includeAnnotationConfig(String includeAnnotationConfig) {
|
||||
if (StringUtils.hasText(includeAnnotationConfig)) {
|
||||
this.includeAnnotationConfig = Boolean.valueOf(includeAnnotationConfig);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
Boolean includeAnnotationConfig() {
|
||||
return this.includeAnnotationConfig;
|
||||
}
|
||||
|
||||
public ComponentScanSpec resourcePattern(String resourcePattern) {
|
||||
if (StringUtils.hasText(resourcePattern)) {
|
||||
this.resourcePattern = resourcePattern;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
String resourcePattern() {
|
||||
return resourcePattern;
|
||||
}
|
||||
|
||||
ComponentScanSpec addBasePackage(String basePackage) {
|
||||
if (StringUtils.hasText(basePackage)) {
|
||||
this.basePackages.add(basePackage);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the set of base packages specified, never {@code null}, never empty
|
||||
* post-validation.
|
||||
* @see #doValidate(SimpleProblemReporter)
|
||||
*/
|
||||
String[] basePackages() {
|
||||
return this.basePackages.toArray(new String[this.basePackages.size()]);
|
||||
}
|
||||
|
||||
public ComponentScanSpec beanNameGenerator(BeanNameGenerator beanNameGenerator) {
|
||||
this.beanNameGenerator = beanNameGenerator;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the class name of the BeanNameGenerator to be used and the ClassLoader
|
||||
* to load it.
|
||||
*/
|
||||
ComponentScanSpec beanNameGenerator(String beanNameGenerator, ClassLoader classLoader) {
|
||||
setClassLoader(classLoader);
|
||||
if (StringUtils.hasText(beanNameGenerator)) {
|
||||
this.beanNameGenerator = beanNameGenerator;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
BeanNameGenerator beanNameGenerator() {
|
||||
return nullSafeTypedObject(this.beanNameGenerator, BeanNameGenerator.class);
|
||||
}
|
||||
|
||||
public ComponentScanSpec scopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) {
|
||||
this.scopeMetadataResolver = scopeMetadataResolver;
|
||||
return this;
|
||||
}
|
||||
|
||||
ComponentScanSpec scopeMetadataResolver(String scopeMetadataResolver, ClassLoader classLoader) {
|
||||
setClassLoader(classLoader);
|
||||
if (StringUtils.hasText(scopeMetadataResolver)) {
|
||||
this.scopeMetadataResolver = scopeMetadataResolver;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
ScopeMetadataResolver scopeMetadataResolver() {
|
||||
return nullSafeTypedObject(this.scopeMetadataResolver, ScopeMetadataResolver.class);
|
||||
}
|
||||
|
||||
public ComponentScanSpec scopedProxyMode(ScopedProxyMode scopedProxyMode) {
|
||||
this.scopedProxyMode = scopedProxyMode;
|
||||
return this;
|
||||
}
|
||||
|
||||
ComponentScanSpec scopedProxyMode(String scopedProxyMode) {
|
||||
if (StringUtils.hasText(scopedProxyMode)) {
|
||||
this.scopedProxyMode = scopedProxyMode;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
ScopedProxyMode scopedProxyMode() {
|
||||
return nullSafeTypedObject(this.scopedProxyMode, ScopedProxyMode.class);
|
||||
}
|
||||
|
||||
public ComponentScanSpec useDefaultFilters(Boolean useDefaultFilters) {
|
||||
this.useDefaultFilters = useDefaultFilters;
|
||||
return this;
|
||||
}
|
||||
|
||||
ComponentScanSpec useDefaultFilters(String useDefaultFilters) {
|
||||
if (StringUtils.hasText(useDefaultFilters)) {
|
||||
this.useDefaultFilters = Boolean.valueOf(useDefaultFilters);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
Boolean useDefaultFilters() {
|
||||
return this.useDefaultFilters;
|
||||
}
|
||||
|
||||
public ComponentScanSpec includeFilters(TypeFilter... includeFilters) {
|
||||
this.includeFilters.clear();
|
||||
for (TypeFilter filter : includeFilters) {
|
||||
addIncludeFilter(filter);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
ComponentScanSpec addIncludeFilter(TypeFilter includeFilter) {
|
||||
Assert.notNull(includeFilter, "includeFilter must not be null");
|
||||
this.includeFilters.add(includeFilter);
|
||||
return this;
|
||||
}
|
||||
|
||||
ComponentScanSpec addIncludeFilter(String filterType, String expression, ClassLoader classLoader) {
|
||||
this.includeFilters.add(new FilterTypeDescriptor(filterType, expression, classLoader));
|
||||
return this;
|
||||
}
|
||||
|
||||
TypeFilter[] includeFilters() {
|
||||
return this.includeFilters.toArray(new TypeFilter[this.includeFilters.size()]);
|
||||
}
|
||||
|
||||
public ComponentScanSpec excludeFilters(TypeFilter... excludeFilters) {
|
||||
this.excludeFilters.clear();
|
||||
for (TypeFilter filter : excludeFilters) {
|
||||
addExcludeFilter(filter);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
ComponentScanSpec addExcludeFilter(TypeFilter excludeFilter) {
|
||||
Assert.notNull(excludeFilter, "excludeFilter must not be null");
|
||||
this.excludeFilters.add(excludeFilter);
|
||||
return this;
|
||||
}
|
||||
|
||||
ComponentScanSpec addExcludeFilter(String filterType, String expression, ClassLoader classLoader) {
|
||||
this.excludeFilters.add(new FilterTypeDescriptor(filterType, expression, classLoader));
|
||||
return this;
|
||||
}
|
||||
|
||||
TypeFilter[] excludeFilters() {
|
||||
return this.excludeFilters.toArray(new TypeFilter[this.excludeFilters.size()]);
|
||||
}
|
||||
|
||||
ComponentScanSpec beanDefinitionDefaults(BeanDefinitionDefaults beanDefinitionDefaults) {
|
||||
this.beanDefinitionDefaults = beanDefinitionDefaults;
|
||||
return this;
|
||||
}
|
||||
|
||||
BeanDefinitionDefaults beanDefinitionDefaults() {
|
||||
return this.beanDefinitionDefaults;
|
||||
}
|
||||
|
||||
ComponentScanSpec autowireCandidatePatterns(String[] autowireCandidatePatterns) {
|
||||
this.autowireCandidatePatterns = autowireCandidatePatterns;
|
||||
return this;
|
||||
}
|
||||
|
||||
String[] autowireCandidatePatterns() {
|
||||
return this.autowireCandidatePatterns;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a ComponentScanSpec from a single string containing
|
||||
* delimited package names.
|
||||
* @see ConfigurableApplicationContext#CONFIG_LOCATION_DELIMITERS
|
||||
*/
|
||||
static ComponentScanSpec forDelimitedPackages(String basePackages) {
|
||||
Assert.notNull(basePackages, "base packages must not be null");
|
||||
return new ComponentScanSpec(
|
||||
StringUtils.tokenizeToStringArray(basePackages,
|
||||
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
|
||||
}
|
||||
|
||||
public void doValidate(ProblemCollector problems) {
|
||||
if(this.basePackages.isEmpty()) {
|
||||
problems.error("At least one base package must be specified");
|
||||
}
|
||||
|
||||
if(this.beanNameGenerator instanceof String) {
|
||||
this.beanNameGenerator = instantiateUserDefinedType("bean name generator", BeanNameGenerator.class, this.beanNameGenerator, this.classLoader, problems);
|
||||
}
|
||||
|
||||
if(this.scopeMetadataResolver instanceof String) {
|
||||
this.scopeMetadataResolver = instantiateUserDefinedType("scope metadata resolver", ScopeMetadataResolver.class, this.scopeMetadataResolver, this.classLoader, problems);
|
||||
}
|
||||
|
||||
if (this.scopedProxyMode instanceof String) {
|
||||
if ("targetClass".equalsIgnoreCase((String)this.scopedProxyMode)) {
|
||||
this.scopedProxyMode = ScopedProxyMode.TARGET_CLASS;
|
||||
}
|
||||
else if ("interfaces".equalsIgnoreCase((String)this.scopedProxyMode)) {
|
||||
this.scopedProxyMode = ScopedProxyMode.INTERFACES;
|
||||
}
|
||||
else if ("no".equalsIgnoreCase((String)this.scopedProxyMode)) {
|
||||
this.scopedProxyMode = ScopedProxyMode.NO;
|
||||
}
|
||||
else {
|
||||
problems.error("invalid scoped proxy mode [%s] supported modes are " +
|
||||
"'no', 'interfaces' and 'targetClass'");
|
||||
this.scopedProxyMode = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.scopeMetadataResolver != null && this.scopedProxyMode != null) {
|
||||
problems.error("Cannot define both scope metadata resolver and scoped proxy mode");
|
||||
}
|
||||
|
||||
for (int i = 0; i < this.includeFilters.size(); i++) {
|
||||
if (this.includeFilters.get(i) instanceof FilterTypeDescriptor) {
|
||||
this.includeFilters.set(i, ((FilterTypeDescriptor)this.includeFilters.get(i)).createTypeFilter(problems));
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < this.excludeFilters.size(); i++) {
|
||||
if (this.excludeFilters.get(i) instanceof FilterTypeDescriptor) {
|
||||
this.excludeFilters.set(i, ((FilterTypeDescriptor)this.excludeFilters.get(i)).createTypeFilter(problems));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Object instantiateUserDefinedType(String description, Class<?> targetType, Object className, ClassLoader classLoader, ProblemCollector problems) {
|
||||
Assert.isInstanceOf(String.class, className, "userType must be of type String");
|
||||
Assert.notNull(classLoader, "classLoader must not be null");
|
||||
Assert.notNull(targetType, "targetType must not be null");
|
||||
Object instance = null;
|
||||
try {
|
||||
instance = classLoader.loadClass((String)className).newInstance();
|
||||
if (!targetType.isAssignableFrom(instance.getClass())) {
|
||||
problems.error(description + " class name must be assignable to " + targetType.getSimpleName());
|
||||
instance = null;
|
||||
}
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
problems.error(String.format(description + " class [%s] not found", className), ex);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
problems.error(String.format("Unable to instantiate %s class [%s] for " +
|
||||
"strategy [%s]. Has a no-argument constructor been provided?",
|
||||
description, className, targetType.getClass().getSimpleName()), ex);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
private void setClassLoader(ClassLoader classLoader) {
|
||||
Assert.notNull(classLoader, "classLoader must not be null");
|
||||
if (this.classLoader == null) {
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
else {
|
||||
Assert.isTrue(this.classLoader == classLoader, "A classLoader has already been assigned " +
|
||||
"and the supplied classLoader is not the same instance. Use the same classLoader " +
|
||||
"for all string-based class properties.");
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> T nullSafeTypedObject(Object object, Class<T> type) {
|
||||
if (object != null) {
|
||||
if (!(type.isAssignableFrom(object.getClass()))) {
|
||||
throw new IllegalStateException(
|
||||
String.format("field must be of type %s but was actually of type %s", type, object.getClass()));
|
||||
}
|
||||
}
|
||||
return (T)object;
|
||||
}
|
||||
|
||||
private static String[] packagesFor(Class<?>[] classes) {
|
||||
ArrayList<String> packages = new ArrayList<String>();
|
||||
for (Class<?> clazz : classes) {
|
||||
packages.add(clazz.getPackage().getName());
|
||||
}
|
||||
return packages.toArray(new String[packages.size()]);
|
||||
}
|
||||
|
||||
|
||||
private static class FilterTypeDescriptor {
|
||||
private String filterType;
|
||||
private String expression;
|
||||
private ClassLoader classLoader;
|
||||
|
||||
FilterTypeDescriptor(String filterType, String expression, ClassLoader classLoader) {
|
||||
Assert.notNull(filterType, "filterType must not be null");
|
||||
Assert.notNull(expression, "expression must not be null");
|
||||
Assert.notNull(classLoader, "classLoader must not be null");
|
||||
this.filterType = filterType;
|
||||
this.expression = expression;
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
TypeFilter createTypeFilter(ProblemCollector problems) {
|
||||
try {
|
||||
if ("annotation".equalsIgnoreCase(this.filterType)) {
|
||||
return new AnnotationTypeFilter((Class<Annotation>) this.classLoader.loadClass(this.expression));
|
||||
}
|
||||
else if ("assignable".equalsIgnoreCase(this.filterType)
|
||||
|| "assignable_type".equalsIgnoreCase(this.filterType)) {
|
||||
return new AssignableTypeFilter(this.classLoader.loadClass(this.expression));
|
||||
}
|
||||
else if ("aspectj".equalsIgnoreCase(this.filterType)) {
|
||||
return new AspectJTypeFilter(this.expression, this.classLoader);
|
||||
}
|
||||
else if ("regex".equalsIgnoreCase(this.filterType)) {
|
||||
return new RegexPatternTypeFilter(Pattern.compile(this.expression));
|
||||
}
|
||||
else if ("custom".equalsIgnoreCase(this.filterType)) {
|
||||
Class<?> filterClass = this.classLoader.loadClass(this.expression);
|
||||
if (!TypeFilter.class.isAssignableFrom(filterClass)) {
|
||||
problems.error(String.format("custom type filter class [%s] must be assignable to %s",
|
||||
this.expression, TypeFilter.class));
|
||||
}
|
||||
return (TypeFilter) BeanUtils.instantiateClass(filterClass);
|
||||
}
|
||||
else {
|
||||
problems.error(String.format("Unsupported filter type [%s]; supported types are: " +
|
||||
"'annotation', 'assignable[_type]', 'aspectj', 'regex', 'custom'", this.filterType));
|
||||
}
|
||||
} catch (ClassNotFoundException ex) {
|
||||
problems.error("Type filter class not found: " + this.expression, ex);
|
||||
} catch (Exception ex) {
|
||||
problems.error(ex.getMessage(), ex.getCause());
|
||||
}
|
||||
|
||||
return new PlaceholderTypeFilter();
|
||||
}
|
||||
|
||||
|
||||
private class PlaceholderTypeFilter implements TypeFilter {
|
||||
|
||||
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
|
||||
throws IOException {
|
||||
throw new UnsupportedOperationException(
|
||||
String.format("match() method for placeholder type filter for " +
|
||||
"{filterType=%s,expression=%s} should never be invoked",
|
||||
filterType, expression));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -33,7 +33,6 @@ import org.springframework.beans.factory.annotation.Autowire;
|
||||
import org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
|
||||
import org.springframework.beans.factory.parsing.Location;
|
||||
import org.springframework.beans.factory.parsing.Problem;
|
||||
import org.springframework.beans.factory.parsing.ProblemReporter;
|
||||
@@ -45,8 +44,8 @@ import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.GenericBeanDefinition;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.context.config.FeatureSpecification;
|
||||
import org.springframework.context.config.SpecificationContext;
|
||||
import org.springframework.context.EnvironmentAware;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.core.Conventions;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.io.Resource;
|
||||
@@ -94,7 +93,7 @@ public class ConfigurationClassBeanDefinitionReader {
|
||||
|
||||
private ResourceLoader resourceLoader;
|
||||
|
||||
private SpecificationContext specificationContext;
|
||||
private Environment environment;
|
||||
|
||||
/**
|
||||
* Create a new {@link ConfigurationClassBeanDefinitionReader} instance that will be used
|
||||
@@ -111,13 +110,7 @@ public class ConfigurationClassBeanDefinitionReader {
|
||||
this.problemReporter = problemReporter;
|
||||
this.metadataReaderFactory = metadataReaderFactory;
|
||||
this.resourceLoader = resourceLoader;
|
||||
// TODO SPR-7420: see about passing in the SpecificationContext created in ConfigurationClassPostProcessor
|
||||
this.specificationContext = new SpecificationContext();
|
||||
this.specificationContext.setRegistry(this.registry);
|
||||
this.specificationContext.setRegistrar(new SimpleComponentRegistrar(this.registry));
|
||||
this.specificationContext.setResourceLoader(this.resourceLoader);
|
||||
this.specificationContext.setEnvironment(environment);
|
||||
this.specificationContext.setProblemReporter(problemReporter);
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
|
||||
@@ -137,7 +130,6 @@ public class ConfigurationClassBeanDefinitionReader {
|
||||
*/
|
||||
private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass) {
|
||||
AnnotationMetadata metadata = configClass.getMetadata();
|
||||
processFeatureAnnotations(metadata);
|
||||
doLoadBeanDefinitionForConfigurationClassIfNecessary(configClass);
|
||||
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
|
||||
loadBeanDefinitionsForBeanMethod(beanMethod);
|
||||
@@ -145,27 +137,6 @@ public class ConfigurationClassBeanDefinitionReader {
|
||||
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
|
||||
}
|
||||
|
||||
private void processFeatureAnnotations(AnnotationMetadata metadata) {
|
||||
try {
|
||||
for (String annotationType : metadata.getAnnotationTypes()) {
|
||||
MetadataReader metadataReader = new SimpleMetadataReaderFactory().getMetadataReader(annotationType);
|
||||
if (metadataReader.getAnnotationMetadata().isAnnotated(FeatureAnnotation.class.getName())) {
|
||||
Map<String, Object> annotationAttributes = metadataReader.getAnnotationMetadata().getAnnotationAttributes(FeatureAnnotation.class.getName(), true);
|
||||
// TODO SPR-7420: this is where we can catch user-defined types and avoid instantiating them for STS purposes
|
||||
FeatureAnnotationParser processor = (FeatureAnnotationParser) BeanUtils.instantiateClass(Class.forName((String)annotationAttributes.get("parser")));
|
||||
FeatureSpecification spec = processor.process(metadata);
|
||||
spec.execute(this.specificationContext);
|
||||
}
|
||||
}
|
||||
} catch (BeanDefinitionParsingException ex) {
|
||||
throw ex;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// TODO SPR-7420: what exception to throw?
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the {@link Configuration} class itself as a bean definition.
|
||||
*/
|
||||
@@ -200,7 +171,7 @@ public class ConfigurationClassBeanDefinitionReader {
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a particular {@link BeanMethod}, registering bean definitions
|
||||
* Read the given {@link BeanMethod}, registering bean definitions
|
||||
* with the BeanDefinitionRegistry based on its contents.
|
||||
*/
|
||||
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
|
||||
@@ -423,8 +394,8 @@ public class ConfigurationClassBeanDefinitionReader {
|
||||
*/
|
||||
private static class InvalidConfigurationImportProblem extends Problem {
|
||||
public InvalidConfigurationImportProblem(String className, Resource resource, AnnotationMetadata metadata) {
|
||||
super(String.format("%s was @Import'ed but is not annotated with @FeatureConfiguration or " +
|
||||
"@Configuration nor does it declare any @Bean methods. Update the class to " +
|
||||
super(String.format("%s was @Import'ed but is not annotated with @Configuration " +
|
||||
"nor does it declare any @Bean methods. Update the class to " +
|
||||
"meet one of these requirements or do not attempt to @Import it.", className),
|
||||
new Location(resource, metadata));
|
||||
}
|
||||
|
||||
@@ -197,15 +197,12 @@ class ConfigurationClassEnhancer {
|
||||
* Enhance a {@link Bean @Bean} method to check the supplied BeanFactory for the
|
||||
* existence of this bean object.
|
||||
*
|
||||
* @throws ProxyCreationException if an early bean reference proxy should be
|
||||
* created but the return type of the bean method being intercepted is not an
|
||||
* interface and thus not a candidate for JDK proxy creation.
|
||||
* @throws Throwable as a catch-all for any exception that may be thrown when
|
||||
* invoking the super implementation of the proxied method i.e., the actual
|
||||
* {@code @Bean} method.
|
||||
*/
|
||||
public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs,
|
||||
MethodProxy cglibMethodProxy) throws ProxyCreationException, Throwable {
|
||||
MethodProxy cglibMethodProxy) throws Throwable {
|
||||
|
||||
String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod);
|
||||
|
||||
|
||||
@@ -16,15 +16,9 @@
|
||||
|
||||
package org.springframework.context.annotation;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -32,12 +26,10 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.DependencyDescriptor;
|
||||
import org.springframework.beans.factory.parsing.FailFastProblemReporter;
|
||||
import org.springframework.beans.factory.parsing.PassThroughSourceExtractor;
|
||||
import org.springframework.beans.factory.parsing.ProblemReporter;
|
||||
@@ -47,23 +39,14 @@ import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
|
||||
import org.springframework.context.EnvironmentAware;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.context.config.FeatureSpecification;
|
||||
import org.springframework.context.config.SourceAwareSpecification;
|
||||
import org.springframework.context.config.SpecificationContext;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
|
||||
import org.springframework.core.type.classreading.MetadataReader;
|
||||
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* {@link BeanFactoryPostProcessor} used for bootstrapping processing of
|
||||
@@ -194,175 +177,13 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
|
||||
}
|
||||
|
||||
/**
|
||||
* Find and process all @Configuration classes with @Feature methods in the given registry.
|
||||
* Find and process all @Configuration classes in the given registry.
|
||||
*/
|
||||
private void processConfigurationClasses(BeanDefinitionRegistry registry) {
|
||||
ConfigurationClassBeanDefinitionReader reader = getConfigurationClassBeanDefinitionReader(registry);
|
||||
processConfigBeanDefinitions(registry, reader);
|
||||
ConfigurationClassParser parser = new ConfigurationClassParser(this.metadataReaderFactory, this.problemReporter, this.environment);
|
||||
processConfigBeanDefinitions(parser, reader, registry);
|
||||
enhanceConfigurationClasses((ConfigurableListableBeanFactory)registry);
|
||||
processFeatureConfigurationClasses((ConfigurableListableBeanFactory) registry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process any @FeatureConfiguration classes
|
||||
*/
|
||||
private void processFeatureConfigurationClasses(final ConfigurableListableBeanFactory beanFactory) {
|
||||
Map<String, Object> featureConfigBeans = retrieveFeatureConfigurationBeans(beanFactory);
|
||||
|
||||
if (featureConfigBeans.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (final Object featureConfigBean : featureConfigBeans.values()) {
|
||||
checkForBeanMethods(featureConfigBean.getClass());
|
||||
}
|
||||
|
||||
if (!cglibAvailable) {
|
||||
throw new IllegalStateException("CGLIB is required to process @FeatureConfiguration classes. " +
|
||||
"Either add CGLIB to the classpath or remove the following @FeatureConfiguration bean definitions: " +
|
||||
featureConfigBeans.keySet());
|
||||
}
|
||||
|
||||
final EarlyBeanReferenceProxyCreator proxyCreator = new EarlyBeanReferenceProxyCreator(beanFactory);
|
||||
final SpecificationContext specificationContext = createSpecificationContext(beanFactory);
|
||||
|
||||
for (final Object featureConfigBean : featureConfigBeans.values()) {
|
||||
ReflectionUtils.doWithMethods(featureConfigBean.getClass(),
|
||||
new ReflectionUtils.MethodCallback() {
|
||||
public void doWith(Method featureMethod) throws IllegalArgumentException, IllegalAccessException {
|
||||
processFeatureMethod(featureMethod, featureConfigBean, specificationContext, proxyCreator);
|
||||
} },
|
||||
new ReflectionUtils.MethodFilter() {
|
||||
public boolean matches(Method candidateMethod) {
|
||||
return candidateMethod.isAnnotationPresent(Feature.class);
|
||||
} });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alternative to {@link ListableBeanFactory#getBeansWithAnnotation(Class)} that avoids
|
||||
* instantiating FactoryBean objects. FeatureConfiguration types cannot be registered as
|
||||
* FactoryBeans, so ignoring them won't cause a problem. On the other hand, using gBWA()
|
||||
* at this early phase of the container would cause all @Bean methods to be invoked, as they
|
||||
* are ultimately FactoryBeans underneath.
|
||||
*/
|
||||
private Map<String, Object> retrieveFeatureConfigurationBeans(ConfigurableListableBeanFactory beanFactory) {
|
||||
Map<String, Object> fcBeans = new HashMap<String, Object>();
|
||||
for (String beanName : beanFactory.getBeanDefinitionNames()) {
|
||||
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
|
||||
if (isFeatureConfiguration(beanDef)) {
|
||||
fcBeans.put(beanName, beanFactory.getBean(beanName));
|
||||
}
|
||||
}
|
||||
return fcBeans;
|
||||
}
|
||||
|
||||
private boolean isFeatureConfiguration(BeanDefinition candidate) {
|
||||
if (!(candidate instanceof AbstractBeanDefinition) || (candidate.getBeanClassName() == null)) {
|
||||
return false;
|
||||
}
|
||||
AbstractBeanDefinition beanDef = (AbstractBeanDefinition) candidate;
|
||||
if (beanDef.hasBeanClass()) {
|
||||
Class<?> beanClass = beanDef.getBeanClass();
|
||||
if (AnnotationUtils.findAnnotation(beanClass, FeatureConfiguration.class) != null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// in the case of @FeatureConfiguration classes included with @Import the bean class name
|
||||
// will still be in String form. Since we don't know whether the current bean definition
|
||||
// is a @FeatureConfiguration or not, carefully check for the annotation using ASM instead
|
||||
// eager classloading.
|
||||
String className = null;
|
||||
try {
|
||||
className = beanDef.getBeanClassName();
|
||||
MetadataReader metadataReader = new SimpleMetadataReaderFactory().getMetadataReader(className);
|
||||
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
|
||||
if (annotationMetadata.isAnnotated(FeatureConfiguration.class.getName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalStateException("Could not create MetadataReader for class " + className, ex);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void checkForBeanMethods(final Class<?> featureConfigClass) {
|
||||
ReflectionUtils.doWithMethods(featureConfigClass,
|
||||
new ReflectionUtils.MethodCallback() {
|
||||
public void doWith(Method beanMethod) throws IllegalArgumentException, IllegalAccessException {
|
||||
throw new FeatureMethodExecutionException(
|
||||
format("@FeatureConfiguration classes must not contain @Bean-annotated methods. " +
|
||||
"%s.%s() is annotated with @Bean and must be removed in order to proceed. " +
|
||||
"Consider moving this method into a dedicated @Configuration class and " +
|
||||
"injecting the bean as a parameter into any @Feature method(s) that need it.",
|
||||
beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName()));
|
||||
} },
|
||||
new ReflectionUtils.MethodFilter() {
|
||||
public boolean matches(Method candidateMethod) {
|
||||
return BeanAnnotationHelper.isBeanAnnotated(candidateMethod);
|
||||
} });
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO SPR-7420: this method invokes user-supplied code, which is not going to fly for STS
|
||||
*
|
||||
* consider introducing some kind of check to see if we're in a tooling context and make guesses
|
||||
* based on return type rather than actually invoking the method and processing the the specification
|
||||
* object that returns.
|
||||
* @param beanFactory
|
||||
* @throws SecurityException
|
||||
*/
|
||||
private void processFeatureMethod(final Method featureMethod, Object configInstance,
|
||||
SpecificationContext specificationContext, EarlyBeanReferenceProxyCreator proxyCreator) {
|
||||
try {
|
||||
// get the return type
|
||||
if (!(FeatureSpecification.class.isAssignableFrom(featureMethod.getReturnType()))) {
|
||||
// TODO SPR-7420: raise a Problem instead?
|
||||
throw new IllegalArgumentException(
|
||||
format("Return type for @Feature method %s.%s() must be assignable to FeatureSpecification",
|
||||
featureMethod.getDeclaringClass().getSimpleName(), featureMethod.getName()));
|
||||
}
|
||||
|
||||
List<Object> beanArgs = new ArrayList<Object>();
|
||||
Class<?>[] parameterTypes = featureMethod.getParameterTypes();
|
||||
for (int i = 0; i < parameterTypes.length; i++) {
|
||||
MethodParameter mp = new MethodParameter(featureMethod, i);
|
||||
DependencyDescriptor dd = new DependencyDescriptor(mp, true, false);
|
||||
Object proxiedBean = proxyCreator.createProxyIfPossible(dd);
|
||||
beanArgs.add(proxiedBean);
|
||||
}
|
||||
|
||||
// reflectively invoke that method
|
||||
FeatureSpecification spec;
|
||||
featureMethod.setAccessible(true);
|
||||
spec = (FeatureSpecification) featureMethod.invoke(configInstance, beanArgs.toArray(new Object[beanArgs.size()]));
|
||||
|
||||
Assert.notNull(spec,
|
||||
format("The specification returned from @Feature method %s.%s() must not be null",
|
||||
featureMethod.getDeclaringClass().getSimpleName(), featureMethod.getName()));
|
||||
|
||||
if (spec instanceof SourceAwareSpecification) {
|
||||
((SourceAwareSpecification)spec).source(featureMethod);
|
||||
((SourceAwareSpecification)spec).sourceName(featureMethod.getName());
|
||||
}
|
||||
spec.execute(specificationContext);
|
||||
} catch (Exception ex) {
|
||||
throw new FeatureMethodExecutionException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private SpecificationContext createSpecificationContext(ConfigurableListableBeanFactory beanFactory) {
|
||||
final BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
|
||||
SpecificationContext specificationContext = new SpecificationContext();
|
||||
specificationContext.setEnvironment(this.environment);
|
||||
specificationContext.setResourceLoader(this.resourceLoader);
|
||||
specificationContext.setRegistry(registry);
|
||||
specificationContext.setRegistrar(new SimpleComponentRegistrar(registry));
|
||||
specificationContext.setProblemReporter(this.problemReporter);
|
||||
return specificationContext;
|
||||
}
|
||||
|
||||
private ConfigurationClassBeanDefinitionReader getConfigurationClassBeanDefinitionReader(BeanDefinitionRegistry registry) {
|
||||
@@ -377,7 +198,7 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
|
||||
* Build and validate a configuration model based on the registry of
|
||||
* {@link Configuration} classes.
|
||||
*/
|
||||
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry, ConfigurationClassBeanDefinitionReader reader) {
|
||||
public void processConfigBeanDefinitions(ConfigurationClassParser parser, ConfigurationClassBeanDefinitionReader reader, BeanDefinitionRegistry registry) {
|
||||
Set<BeanDefinitionHolder> configCandidates = new LinkedHashSet<BeanDefinitionHolder>();
|
||||
for (String beanName : registry.getBeanDefinitionNames()) {
|
||||
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
|
||||
@@ -391,8 +212,7 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
|
||||
return;
|
||||
}
|
||||
|
||||
// Populate a new configuration model by parsing each @Configuration classes
|
||||
ConfigurationClassParser parser = new ConfigurationClassParser(this.metadataReaderFactory, this.problemReporter, this.environment);
|
||||
// Parse each @Configuration class
|
||||
for (BeanDefinitionHolder holder : configCandidates) {
|
||||
BeanDefinition bd = holder.getBeanDefinition();
|
||||
try {
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.context.annotation;
|
||||
|
||||
import org.springframework.beans.factory.parsing.Location;
|
||||
import org.springframework.beans.factory.parsing.ProblemReporter;
|
||||
import org.springframework.core.type.MethodMetadata;
|
||||
|
||||
/**
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
*/
|
||||
abstract class ConfigurationMethod {
|
||||
|
||||
protected final MethodMetadata metadata;
|
||||
|
||||
protected final ConfigurationClass configurationClass;
|
||||
|
||||
|
||||
public ConfigurationMethod(MethodMetadata metadata, ConfigurationClass configurationClass) {
|
||||
this.metadata = metadata;
|
||||
this.configurationClass = configurationClass;
|
||||
}
|
||||
|
||||
public MethodMetadata getMetadata() {
|
||||
return this.metadata;
|
||||
}
|
||||
|
||||
public ConfigurationClass getConfigurationClass() {
|
||||
return this.configurationClass;
|
||||
}
|
||||
|
||||
public Location getResourceLocation() {
|
||||
return new Location(this.configurationClass.getResource(), this.metadata);
|
||||
}
|
||||
|
||||
public void validate(ProblemReporter problemReporter) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("[%s:name=%s,declaringClass=%s]",
|
||||
this.getClass().getSimpleName(), this.getMetadata().getMethodName(), this.getMetadata().getDeclaringClassName());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.context.annotation;
|
||||
|
||||
/**
|
||||
* Marker interface indicating that an object is a proxy for a bean referenced
|
||||
* from within a {@link Feature @Feature} method.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
*/
|
||||
public interface EarlyBeanReferenceProxy {
|
||||
|
||||
Object dereferenceTargetBean();
|
||||
|
||||
}
|
||||
@@ -1,254 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.context.annotation;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import net.sf.cglib.proxy.Callback;
|
||||
import net.sf.cglib.proxy.CallbackFilter;
|
||||
import net.sf.cglib.proxy.Enhancer;
|
||||
import net.sf.cglib.proxy.MethodInterceptor;
|
||||
import net.sf.cglib.proxy.MethodProxy;
|
||||
|
||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||
import org.springframework.beans.factory.config.DependencyDescriptor;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* Creates proxies for beans referenced from within @Feature methods.
|
||||
*
|
||||
* TODO SPR-7420: document
|
||||
* - discuss why proxies are important (avoiding side effects of early instantiation)
|
||||
* - discuss benefits of interface-based proxies over concrete proxies
|
||||
* - make it clear that both of the above are possible
|
||||
* - discuss invocation of @Bean methods and how they too return proxies.
|
||||
* this 'proxy returning a proxy' approach can be confusing at first, but the
|
||||
* implementation should help in making it clear.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
*/
|
||||
class EarlyBeanReferenceProxyCreator {
|
||||
|
||||
static final String MISSING_NO_ARG_CONSTRUCTOR_ERROR_MESSAGE =
|
||||
"Cannot create subclass proxy for bean type %s because it does not have a no-arg constructor. " +
|
||||
"Add a no-arg constructor or attempt to inject the bean by interface rather than by concrete class.";
|
||||
|
||||
static final String PRIVATE_NO_ARG_CONSTRUCTOR_ERROR_MESSAGE =
|
||||
"Cannot create subclass proxy for bean type %s because its no-arg constructor is private. " +
|
||||
"Increase the visibility of the no-arg constructor or attempt to inject the bean by interface rather " +
|
||||
"than by concrete class.";
|
||||
|
||||
private final AutowireCapableBeanFactory beanFactory;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new proxy creator that will dereference proxy target beans against
|
||||
* the given bean factory.
|
||||
*/
|
||||
public EarlyBeanReferenceProxyCreator(AutowireCapableBeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a proxy that will ultimately dereference its target object using
|
||||
* the given dependency descriptor. No proxy is created if the dependency type
|
||||
* is final, rather the dependency is resolved immediately. This is important
|
||||
* especially with regard to supporting @Value injection.
|
||||
*/
|
||||
public Object createProxyIfPossible(DependencyDescriptor descriptor) {
|
||||
if (Modifier.isFinal(descriptor.getDependencyType().getModifiers())) {
|
||||
return beanFactory.resolveDependency(descriptor, "");
|
||||
}
|
||||
return doCreateProxy(new ResolveDependencyTargetBeanDereferencingInterceptor(descriptor));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a proxy that looks up target beans using the given dereferencing interceptor.
|
||||
*
|
||||
* @see EarlyBeanReferenceProxy#dereferenceTargetBean()
|
||||
*/
|
||||
private Object doCreateProxy(TargetBeanDereferencingInterceptor targetBeanDereferencingInterceptor) {
|
||||
Enhancer enhancer = new Enhancer();
|
||||
Class<?> targetBeanType = targetBeanDereferencingInterceptor.getTargetBeanType();
|
||||
if (targetBeanType.isInterface()) {
|
||||
enhancer.setSuperclass(Object.class);
|
||||
enhancer.setInterfaces(new Class<?>[] {targetBeanType, EarlyBeanReferenceProxy.class});
|
||||
} else {
|
||||
assertClassIsProxyCapable(targetBeanType);
|
||||
enhancer.setSuperclass(targetBeanType);
|
||||
enhancer.setInterfaces(new Class<?>[] {EarlyBeanReferenceProxy.class});
|
||||
}
|
||||
enhancer.setCallbacks(new Callback[] {
|
||||
new BeanMethodInterceptor(),
|
||||
new ObjectMethodsInterceptor(),
|
||||
targetBeanDereferencingInterceptor,
|
||||
new TargetBeanDelegatingMethodInterceptor()
|
||||
});
|
||||
enhancer.setCallbackFilter(new CallbackFilter() {
|
||||
public int accept(Method method) {
|
||||
if (BeanAnnotationHelper.isBeanAnnotated(method)) {
|
||||
return 0;
|
||||
}
|
||||
if (ReflectionUtils.isObjectMethod(method)) {
|
||||
return 1;
|
||||
}
|
||||
if (method.getName().equals("dereferenceTargetBean")) {
|
||||
return 2;
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
});
|
||||
return enhancer.create();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the given class is capable of being subclass proxied by CGLIB.
|
||||
*/
|
||||
private static void assertClassIsProxyCapable(Class<?> clazz) {
|
||||
Assert.isTrue(!clazz.isInterface(), "class parameter must be a concrete type");
|
||||
try {
|
||||
// attempt to retrieve the no-arg constructor for the class
|
||||
Constructor<?> noArgCtor = clazz.getDeclaredConstructor();
|
||||
if ((noArgCtor.getModifiers() & Modifier.PRIVATE) != 0) {
|
||||
throw new ProxyCreationException(String.format(PRIVATE_NO_ARG_CONSTRUCTOR_ERROR_MESSAGE, clazz.getName()));
|
||||
}
|
||||
} catch (NoSuchMethodException ex) {
|
||||
throw new ProxyCreationException(String.format(MISSING_NO_ARG_CONSTRUCTOR_ERROR_MESSAGE, clazz.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Interceptor for @Bean-annotated methods called from early-proxied bean instances, such as
|
||||
* @Configuration class instances. Invoking instance methods on early-proxied beans usually
|
||||
* causes an eager bean lookup, but in the case of @Bean methods, it is important to return
|
||||
* a proxy.
|
||||
*/
|
||||
private class BeanMethodInterceptor implements MethodInterceptor {
|
||||
|
||||
public Object intercept(Object obj, final Method beanMethod, Object[] args, MethodProxy proxy) throws Throwable {
|
||||
return doCreateProxy(new ByNameLookupTargetBeanDereferencingInterceptor(beanMethod));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Interceptor for methods declared by java.lang.Object()
|
||||
*/
|
||||
private static class ObjectMethodsInterceptor implements MethodInterceptor {
|
||||
|
||||
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
|
||||
if (method.getName().equals("toString")) {
|
||||
return String.format("EarlyBeanReferenceProxy for bean of type %s",
|
||||
obj.getClass().getSuperclass().getSimpleName());
|
||||
}
|
||||
if (method.getName().equals("hashCode")) {
|
||||
return System.identityHashCode(obj);
|
||||
}
|
||||
if (method.getName().equals("equals")) {
|
||||
return obj == args[0];
|
||||
}
|
||||
if (method.getName().equals("finalize")) {
|
||||
return null;
|
||||
}
|
||||
return proxy.invokeSuper(obj, args);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Strategy interface allowing for various approaches to dereferencing (i.e. 'looking up')
|
||||
* the target bean for an early bean reference proxy.
|
||||
*
|
||||
* @see EarlyBeanReferenceProxy#dereferenceTargetBean()
|
||||
*/
|
||||
private interface TargetBeanDereferencingInterceptor extends MethodInterceptor {
|
||||
Class<?> getTargetBeanType();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Interceptor that dereferences the target bean for the proxy by calling
|
||||
* {@link AutowireCapableBeanFactory#resolveDependency(DependencyDescriptor, String)}.
|
||||
*
|
||||
* @see EarlyBeanReferenceProxy#dereferenceTargetBean()
|
||||
*/
|
||||
private class ResolveDependencyTargetBeanDereferencingInterceptor implements TargetBeanDereferencingInterceptor {
|
||||
|
||||
private final DependencyDescriptor descriptor;
|
||||
|
||||
public ResolveDependencyTargetBeanDereferencingInterceptor(DependencyDescriptor descriptor) {
|
||||
this.descriptor = descriptor;
|
||||
}
|
||||
|
||||
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
|
||||
return beanFactory.resolveDependency(descriptor, null);
|
||||
}
|
||||
|
||||
public Class<?> getTargetBeanType() {
|
||||
return this.descriptor.getDependencyType();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Interceptor that dereferences the target bean for the proxy by calling BeanFactory#getBean(String).
|
||||
*
|
||||
* @see EarlyBeanReferenceProxy#dereferenceTargetBean()
|
||||
*/
|
||||
private class ByNameLookupTargetBeanDereferencingInterceptor implements TargetBeanDereferencingInterceptor {
|
||||
|
||||
private final Method beanMethod;
|
||||
|
||||
public ByNameLookupTargetBeanDereferencingInterceptor(Method beanMethod) {
|
||||
this.beanMethod = beanMethod;
|
||||
}
|
||||
|
||||
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
|
||||
return beanFactory.getBean(BeanAnnotationHelper.determineBeanNameFor(beanMethod));
|
||||
}
|
||||
|
||||
public Class<?> getTargetBeanType() {
|
||||
return beanMethod.getReturnType();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Interceptor that dereferences the target bean for the proxy and delegates the
|
||||
* current method call to it.
|
||||
* @see TargetBeanDereferencingInterceptor
|
||||
*/
|
||||
private static class TargetBeanDelegatingMethodInterceptor implements MethodInterceptor {
|
||||
|
||||
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
|
||||
Object targetBean = ((EarlyBeanReferenceProxy)obj).dereferenceTargetBean();
|
||||
return method.invoke(targetBean, args);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.context.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* TODO SPR-7420: document
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface Feature {
|
||||
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.context.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Meta-annotation indicating that an annotation should be processed
|
||||
* to produce a {@code FeatureSpecification}.
|
||||
*
|
||||
* <p>See {@link ComponentScan @ComponentScan} for an implementation example.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
* @see ComponentScan
|
||||
* @see org.springframework.context.config.FeatureSpecification
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.ANNOTATION_TYPE)
|
||||
public @interface FeatureAnnotation {
|
||||
|
||||
/**
|
||||
* Indicate the class that should be used to parse this annotation
|
||||
* into a {@code FeatureSpecification}.
|
||||
*/
|
||||
Class<? extends FeatureAnnotationParser> parser();
|
||||
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.context.annotation;
|
||||
|
||||
import org.springframework.context.config.FeatureSpecification;
|
||||
import org.springframework.context.config.FeatureSpecificationExecutor;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
|
||||
/**
|
||||
* Interface for parsing {@link AnnotationMetadata} from a {@link FeatureAnnotation}
|
||||
* into a {@link FeatureSpecification} object. Used in conjunction with a
|
||||
* {@link FeatureSpecificationExecutor} to provide a source-agnostic approach to
|
||||
* handling configuration metadata.
|
||||
*
|
||||
* <p>For example, Spring's component-scanning can be configured via XML using
|
||||
* the {@code context:component-scan} element or via the {@link ComponentScan}
|
||||
* annotation. In either case, the metadata is the same -- only the source
|
||||
* format differs. {@link ComponentScanBeanDefinitionParser} is used to create
|
||||
* a specification from the {@code <context:component-scan>} XML element, while
|
||||
* {@link ComponentScanAnnotationParser} creates a specification from the
|
||||
* the annotation style. They both produce a {@link ComponentScanSpec}
|
||||
* object that is ultimately delegated to a {@link ComponentScanExecutor}
|
||||
* which understands how to configure a {@link ClassPathBeanDefinitionScanner},
|
||||
* perform actual scanning, and register actual bean definitions against the
|
||||
* container.
|
||||
*
|
||||
* <p>Implementations must be instantiable via a no-arg constructor.
|
||||
*
|
||||
* TODO SPR-7420: documentation (clean up)
|
||||
* TODO SPR-7420: rework so annotations declare their creator.
|
||||
*
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
* @see FeatureAnnotation#parser()
|
||||
* @see FeatureSpecification
|
||||
* @see FeatureSpecificationExecutor
|
||||
*/
|
||||
public interface FeatureAnnotationParser {
|
||||
|
||||
/**
|
||||
* Parse the given annotation metadata and populate a {@link FeatureSpecification}
|
||||
* object suitable for execution by a {@link FeatureSpecificationExecutor}.
|
||||
*/
|
||||
FeatureSpecification process(AnnotationMetadata metadata);
|
||||
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.context.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* TODO SPR-7420: document
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
* @see Configuration
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Component
|
||||
public @interface FeatureConfiguration {
|
||||
|
||||
/**
|
||||
* Explicitly specify the name of the Spring bean definition associated
|
||||
* with this FeatureConfiguration class. If left unspecified (the common case),
|
||||
* a bean name will be automatically generated.
|
||||
*
|
||||
* <p>The custom name applies only if the FeatureConfiguration class is picked up via
|
||||
* component scanning or supplied directly to a {@link AnnotationConfigApplicationContext}.
|
||||
* If the FeatureConfiguration class is registered as a traditional XML bean definition,
|
||||
* the name/id of the bean element will take precedence.
|
||||
*
|
||||
* @return the specified bean name, if any
|
||||
* @see org.springframework.beans.factory.support.DefaultBeanNameGenerator
|
||||
*/
|
||||
String value() default "";
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.context.annotation;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
class FeatureMethodExecutionException extends RuntimeException {
|
||||
public FeatureMethodExecutionException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public FeatureMethodExecutionException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.context.annotation;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
class ProxyCreationException extends RuntimeException {
|
||||
|
||||
public ProxyCreationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.context.annotation;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.parsing.ComponentDefinition;
|
||||
import org.springframework.beans.factory.parsing.ComponentRegistrar;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
|
||||
/**
|
||||
* TODO SPR-7420: document
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
*/
|
||||
class SimpleComponentRegistrar implements ComponentRegistrar {
|
||||
|
||||
private final BeanDefinitionRegistry registry;
|
||||
|
||||
public SimpleComponentRegistrar(BeanDefinitionRegistry registry) {
|
||||
this.registry = registry;
|
||||
}
|
||||
|
||||
public String registerWithGeneratedName(BeanDefinition beanDefinition) {
|
||||
return BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, this.registry);
|
||||
}
|
||||
|
||||
public void registerBeanComponent(BeanComponentDefinition component) {
|
||||
BeanDefinitionReaderUtils.registerBeanDefinition(component, this.registry);
|
||||
registerComponent(component);
|
||||
}
|
||||
|
||||
public void registerComponent(ComponentDefinition component) {
|
||||
// no-op
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.context.config;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.parsing.ProblemCollector;
|
||||
import org.springframework.beans.factory.parsing.ProblemReporter;
|
||||
import org.springframework.beans.factory.parsing.SimpleProblemCollector;
|
||||
|
||||
|
||||
/**
|
||||
* TODO SPR-7420: document
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
*/
|
||||
public abstract class AbstractFeatureSpecification implements SourceAwareSpecification {
|
||||
|
||||
private static final Object DUMMY_SOURCE = new Object();
|
||||
private static final String DUMMY_SOURCE_NAME = "dummySource";
|
||||
|
||||
protected Class<? extends FeatureSpecificationExecutor> executorType;
|
||||
|
||||
private Object source = DUMMY_SOURCE;
|
||||
private String sourceName = DUMMY_SOURCE_NAME;
|
||||
|
||||
protected AbstractFeatureSpecification(Class<? extends FeatureSpecificationExecutor> executorType) {
|
||||
this.executorType = executorType;
|
||||
}
|
||||
|
||||
public final boolean validate(ProblemReporter problemReporter) {
|
||||
ProblemCollector collector = new SimpleProblemCollector(this.source());
|
||||
this.doValidate(collector);
|
||||
collector.reportProblems(problemReporter);
|
||||
return collector.hasErrors() ? false : true;
|
||||
}
|
||||
|
||||
protected abstract void doValidate(ProblemCollector problems);
|
||||
|
||||
public AbstractFeatureSpecification source(Object source) {
|
||||
this.source = source;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Object source() {
|
||||
return this.source;
|
||||
}
|
||||
|
||||
public AbstractFeatureSpecification sourceName(String sourceName) {
|
||||
this.sourceName = sourceName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String sourceName() {
|
||||
return this.sourceName;
|
||||
}
|
||||
|
||||
public void execute(SpecificationContext specificationContext) {
|
||||
FeatureSpecificationExecutor executor =
|
||||
BeanUtils.instantiateClass(this.executorType);
|
||||
executor.execute(this, specificationContext);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.context.config;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.parsing.ComponentRegistrarAdapter;
|
||||
import org.springframework.beans.factory.parsing.ProblemReporter;
|
||||
import org.springframework.beans.factory.parsing.ReaderContext;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.core.env.DefaultEnvironment;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* TODO SPR-7420: document
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
*/
|
||||
public abstract class AbstractSpecificationBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
public final BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
FeatureSpecification spec = doParse(element, parserContext);
|
||||
if (spec instanceof SourceAwareSpecification) {
|
||||
((SourceAwareSpecification)spec).source(parserContext.getReaderContext().extractSource(element));
|
||||
((SourceAwareSpecification)spec).sourceName(element.getTagName());
|
||||
}
|
||||
spec.execute(specificationContextFrom(parserContext));
|
||||
return null;
|
||||
}
|
||||
|
||||
abstract protected FeatureSpecification doParse(Element element, ParserContext parserContext);
|
||||
|
||||
/**
|
||||
* Adapt the given ParserContext into a SpecificationContext.
|
||||
*/
|
||||
private SpecificationContext specificationContextFrom(ParserContext parserContext) {
|
||||
SpecificationContext specContext = new SpecificationContext();
|
||||
specContext.setRegistry(parserContext.getRegistry());
|
||||
specContext.setRegistrar(new ComponentRegistrarAdapter(parserContext));
|
||||
specContext.setResourceLoader(parserContext.getReaderContext().getResourceLoader());
|
||||
try {
|
||||
// again, STS constraints around the addition of the new getEnvironment()
|
||||
// method in 3.1.0 (it's not present in STS current spring version, 3.0.5)
|
||||
// TODO 3.1 GA: remove this block prior to 3.1 GA
|
||||
specContext.setEnvironment(parserContext.getDelegate().getEnvironment());
|
||||
} catch (NoSuchMethodError ex) {
|
||||
specContext.setEnvironment(new DefaultEnvironment());
|
||||
}
|
||||
try {
|
||||
// access the reader context's problem reporter reflectively in order to
|
||||
// compensate for tooling (STS) constraints around introduction of changes
|
||||
// to parser context / reader context classes.
|
||||
// TODO 3.1 GA: remove this block prior to 3.1 GA
|
||||
Field field = ReaderContext.class.getDeclaredField("problemReporter");
|
||||
field.setAccessible(true);
|
||||
ProblemReporter problemReporter = (ProblemReporter)field.get(parserContext.getReaderContext());
|
||||
specContext.setProblemReporter(problemReporter);
|
||||
} catch (Exception ex) {
|
||||
throw new IllegalStateException(
|
||||
"Could not access field 'ReaderContext#problemReporter' on object " +
|
||||
parserContext.getReaderContext(), ex);
|
||||
}
|
||||
return specContext;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.context.config;
|
||||
|
||||
import org.springframework.core.GenericTypeResolver;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* TODO SPR-7420: document
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
*/
|
||||
public abstract class AbstractSpecificationExecutor<S extends FeatureSpecification> implements FeatureSpecificationExecutor {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>This implementation {@linkplain FeatureSpecification#validate() validates} the
|
||||
* given specification and delegates it to {@link #doExecute(FeatureSpecification)}
|
||||
* only if valid.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public final void execute(FeatureSpecification spec, SpecificationContext specificationContext) {
|
||||
Assert.notNull(spec, "Specification must not be null");
|
||||
Assert.notNull(spec, "SpecificationContext must not be null");
|
||||
Class<?> typeArg = GenericTypeResolver.resolveTypeArgument(this.getClass(), AbstractSpecificationExecutor.class);
|
||||
Assert.isTrue(typeArg.equals(spec.getClass()), "Specification cannot be executed by this executor");
|
||||
if (spec.validate(specificationContext.getProblemReporter())) {
|
||||
doExecute((S)spec, specificationContext);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the given specification, usually resulting in registration of bean definitions
|
||||
* against a bean factory.
|
||||
* @param specification the {@linkplain FeatureSpecification#validate() validated} specification
|
||||
*/
|
||||
protected abstract void doExecute(S specification, SpecificationContext specificationContext);
|
||||
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.context.config;
|
||||
|
||||
import org.springframework.beans.factory.parsing.ProblemReporter;
|
||||
|
||||
/**
|
||||
* Interface to be implemented by objects that specify the configuration of a particular feature
|
||||
* of the Spring container e.g., component-scanning, JMX MBean exporting, AspectJ auto-proxying,
|
||||
* annotation-driven transaction management, and so on.
|
||||
*
|
||||
* <p>Many features of the Spring container can be configured using either XML or annotations.
|
||||
* As one example, Spring's <em>component scanning</em> feature may be configured using
|
||||
* either the {@code <context:component-scan>} XML element or (as of Spring 3.1) the
|
||||
* {@code @ComponentScan} annotation. These two options are equivalent to one another, and users may
|
||||
* choose between them as a matter of convention or preference. Fundamentally, both are declarative
|
||||
* mechanisms for <em>specifying</em> how the Spring container should be configured. A {@code
|
||||
* FeatureSpecification} object, then, is a way of representing this configuration information independent
|
||||
* of its original source format be it XML, annotations, or otherwise.
|
||||
*
|
||||
* <p>A {@code FeatureSpecification} is responsible for {@linkplain #validate validating itself}.
|
||||
* For example, a component-scanning specification would check that at least one base package has
|
||||
* been specified, and otherwise register a {@code Problem} with a {@link ProblemReporter}. Taking
|
||||
* this approach as opposed to throwing exceptions allows for maximum tooling and error reporting
|
||||
* flexibility.
|
||||
*
|
||||
* <p>A {@link FeatureSpecificationExecutor} is used to carry out the instructions within a populated
|
||||
* {@code FeatureSpecification}; this is where the "real work" happens. In the case of component scanning
|
||||
* as above, it is within a {@code FeatureSpecificationExecutor} that a bean definition scanner is created,
|
||||
* configured and invoked against the base packages specified.
|
||||
*
|
||||
* <p>{@code FeatureSpecification} objects may be populated and executed by Spring XML namespace element
|
||||
* parsers on order to separate the concerns of XML parsing from Spring bean definition creation and
|
||||
* registration. This type of use is mostly a framework-internal matter. More interesting to end users is
|
||||
* the use of {@code FeatureSpecification} objects within {@code @FeatureConfiguration} classes and their
|
||||
* {@code @Feature} methods. This functionality is new in Spring 3.1 and is the logical evolution of Spring's
|
||||
* Java-based configuration support first released in Spring 3.0 (see {@code @Configuration} classes and
|
||||
* {@code @Bean} methods). The primary goal of {@code Feature}-related support is to round out this
|
||||
* Java-based support and allow users to configure all aspects of the Spring-container without requiring
|
||||
* the use of XML. See "design notes" below for an example of this kind of use.
|
||||
*
|
||||
* <h2>Notes on designing {@code FeatureSpecification} implementations</h2>
|
||||
*
|
||||
* <p>The public API of a {@code FeatureSpecification} should be designed for maximum ease of use
|
||||
* within {@code @Feature} methods. Traditional JavaBean-style getters and setters should be dropped
|
||||
* for a more fluent style that allows for method chaining. Consider the following example of a
|
||||
* {@code @Feature} method:
|
||||
*
|
||||
* <pre>
|
||||
* @Feature
|
||||
* public TxAnnotationDriven tx(PlatformTransactionManager txManager) {
|
||||
* return new TxAnnotationDriven(txManager).proxyTargetClass(true);
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* Notice how the creation and configuration of the {@code TxAnnotationDriven} specification is
|
||||
* concise and reads well. This is facilitated by mutator methods that always return the
|
||||
* specification object's 'this' reference, allowing for method chaining. A secondary design goal
|
||||
* of this approach is that the resulting code tends to mirror corresponding XML namespace
|
||||
* declarations, which most Spring users are already familiar with. For example, compare the
|
||||
* code above with its XML counterpart:
|
||||
*
|
||||
* <p>{@code <tx:annotation-driven transaction-manager="txManager" proxy-target-class="true"/>}
|
||||
*
|
||||
* <p>Typically, a user will call only the constructor and 'mutator' methods of a specification
|
||||
* object. The accessor/getter methods, however, are typically called only by the specification's
|
||||
* {@linkplain FeatureSpecificationExecutor executor} for the purpose of populating and registering
|
||||
* bean definitions with the Spring container. For this reason, it is recommended that accessor
|
||||
* methods be given package-private visibility. This creates a better experience for users from
|
||||
* an IDE content-assist point of view as they will see only the public mutator methods, reducing
|
||||
* any possible confusion.
|
||||
*
|
||||
* <p>Implementations should take care to allow for use of string-based bean names, placeholder
|
||||
* (<code>"${...}"</code>) and SpEL (<code>"#{...}</code>) expressions wherever they may be useful.
|
||||
* While it is generally desirable to refer to dependent beans in pure Java, in certain cases a
|
||||
* user may wish or need to refer to a bean by name. For example, the {@code TxAnnotationDriven} specification
|
||||
* referenced above allows for specifying its transaction-manager reference by {@code String} or by
|
||||
* {@code PlatformTransactionManager} reference. Such strings should always be candidates for placeholder
|
||||
* replacement and SpEL evaluation for maximum configurability as well as parity with the feature set
|
||||
* available in Spring XML. With regard to SpEL expressions, users should assume that only expressions
|
||||
* evaluating to a bean name will be supported. While it is technically possible with SpEL to resolve
|
||||
* a bean instance, specification executors will not support such use unless explicitly indicated.
|
||||
*
|
||||
* <p>See the Javadoc for {@code @FeatureConfiguration} classes and {@code @Feature} methods for
|
||||
* information on their lifecycle and semantics.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
* @see FeatureSpecificationExecutor
|
||||
* @see AbstractSpecificationExecutor
|
||||
* @see org.springframework.context.annotation.Feature
|
||||
* @see org.springframework.context.annotation.FeatureConfiguration
|
||||
*/
|
||||
public interface FeatureSpecification {
|
||||
|
||||
/**
|
||||
* Validate this specification instance to ensure all required properties
|
||||
* have been set, including checks on mutually exclusive or mutually
|
||||
* dependent properties. May in some cases modify the state of the
|
||||
* specification e.g., instantiating types specified as strings.
|
||||
* @see AbstractSpecificationExecutor#execute(FeatureSpecification, SpecificationContext)
|
||||
* @return whether any problems occurred during validation
|
||||
*/
|
||||
boolean validate(ProblemReporter problemReporter);
|
||||
|
||||
/**
|
||||
* Execute this specification instance, carrying out the instructions
|
||||
* specified within. Should work by delegating to an underlying
|
||||
* {@link FeatureSpecificationExecutor} for proper separation of concerns.
|
||||
*/
|
||||
void execute(SpecificationContext specificationContext);
|
||||
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.context.config;
|
||||
|
||||
/**
|
||||
* Interface for executing a populated {@link FeatureSpecification}. Provides
|
||||
* a generic mechanism for handling container configuration metadata regardless of
|
||||
* origin in XML, annotations, or other source format.
|
||||
*
|
||||
* TODO SPR-7420: document (clean up)
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
* @see AbstractSpecificationExecutor
|
||||
* @see org.springframework.beans.factory.xml.BeanDefinitionParser
|
||||
* @see org.springframework.context.annotation.FeatureAnnotationParser
|
||||
* @see org.springframework.context.annotation.ComponentScanExecutor
|
||||
*/
|
||||
public interface FeatureSpecificationExecutor {
|
||||
|
||||
/**
|
||||
* Execute the given specification, usually resulting in registration
|
||||
* of bean definitions against a bean factory.
|
||||
*/
|
||||
void execute(FeatureSpecification spec, SpecificationContext specificationContext);
|
||||
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.context.config;
|
||||
|
||||
/**
|
||||
* TODO SPR-7420: document
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
*/
|
||||
public interface SourceAwareSpecification extends FeatureSpecification {
|
||||
|
||||
String sourceName();
|
||||
|
||||
SourceAwareSpecification sourceName(String sourceName);
|
||||
|
||||
Object source();
|
||||
|
||||
SourceAwareSpecification source(Object source);
|
||||
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.context.config;
|
||||
|
||||
import org.springframework.beans.factory.parsing.ComponentRegistrar;
|
||||
import org.springframework.beans.factory.parsing.ProblemReporter;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
|
||||
/**
|
||||
* TODO: rename to SpecificationContext?
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
*/
|
||||
public class SpecificationContext {
|
||||
|
||||
private BeanDefinitionRegistry registry;
|
||||
private ComponentRegistrar registrar;
|
||||
private ResourceLoader resourceLoader;
|
||||
private Environment environment;
|
||||
private ProblemReporter problemReporter;
|
||||
|
||||
public SpecificationContext() { }
|
||||
|
||||
public void setRegistry(BeanDefinitionRegistry registry) {
|
||||
this.registry = registry;
|
||||
}
|
||||
|
||||
public BeanDefinitionRegistry getRegistry() {
|
||||
return this.registry;
|
||||
}
|
||||
|
||||
public void setRegistrar(ComponentRegistrar registrar) {
|
||||
this.registrar = registrar;
|
||||
}
|
||||
|
||||
public ComponentRegistrar getRegistrar() {
|
||||
return this.registrar;
|
||||
}
|
||||
|
||||
public void setResourceLoader(ResourceLoader resourceLoader) {
|
||||
this.resourceLoader = resourceLoader;
|
||||
}
|
||||
|
||||
public ResourceLoader getResourceLoader() {
|
||||
return this.resourceLoader;
|
||||
}
|
||||
|
||||
public void setEnvironment(Environment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
public Environment getEnvironment() {
|
||||
return this.environment;
|
||||
}
|
||||
|
||||
public void setProblemReporter(ProblemReporter problemReporter) {
|
||||
this.problemReporter = problemReporter;
|
||||
}
|
||||
|
||||
public ProblemReporter getProblemReporter() {
|
||||
return this.problemReporter;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user