Skip to content

Commit b4fea47

Browse files
committed
Introduce FeatureSpecification support
Introduce FeatureSpecification interface and implementations FeatureSpecification objects decouple the configuration of spring container features from the concern of parsing XML namespaces, allowing for reuse in code-based configuration (see @feature* annotations below). * ComponentScanSpec * TxAnnotationDriven * MvcAnnotationDriven * MvcDefaultServletHandler * MvcResources * MvcViewControllers Refactor associated BeanDefinitionParsers to delegate to new impls above The following BeanDefinitionParser implementations now deal only with the concern of XML parsing. Validation is handled by their corresponding FeatureSpecification object. Bean definition creation and registration is handled by their corresponding FeatureSpecificationExecutor type. * ComponentScanBeanDefinitionParser * AnnotationDrivenBeanDefinitionParser (tx) * AnnotationDrivenBeanDefinitionParser (mvc) * DefaultServletHandlerBeanDefinitionParser * ResourcesBeanDefinitionParser * ViewControllerBeanDefinitionParser Update AopNamespaceUtils to decouple from XML (DOM API) Methods necessary for executing TxAnnotationDriven specification (and eventually, the AspectJAutoProxy specification) have been added that accept boolean arguments for whether to proxy target classes and whether to expose the proxy via threadlocal. Methods that accepted and introspected DOM Element objects still exist but have been deprecated. Introduce @FeatureConfiguration classes and @feature methods Allow for creation and configuration of FeatureSpecification objects at the user level. A companion for @configuration classes allowing for completely code-driven configuration of the Spring container. See changes in ConfigurationClassPostProcessor for implementation details. See Feature*Tests for usage examples. FeatureTestSuite in .integration-tests is a JUnit test suite designed to aggregate all BDP and Feature* related tests for a convenient way to confirm that Feature-related changes don't break anything. Uncomment this test and execute from Eclipse / IDEA. Due to classpath issues, this cannot be compiled by Ant/Ivy at the command line. Introduce @FeatureAnnotation meta-annotation and @componentscan impl @FeatureAnnotation provides an alternate mechanism for creating and executing FeatureSpecification objects. See @componentscan and its corresponding ComponentScanAnnotationParser implementation for details. See ComponentScanAnnotationIntegrationTests for usage examples Introduce Default[Formatting]ConversionService implementations Allows for convenient instantiation of ConversionService objects containing defaults appropriate for most environments. Replaces similar support originally in ConversionServiceFactory (which is now deprecated). This change was justified by the need to avoid use of FactoryBeans in @configuration classes (such as FormattingConversionServiceFactoryBean). It is strongly preferred that users simply instantiate and configure the objects that underlie our FactoryBeans. In the case of the ConversionService types, the easiest way to do this is to create Default* subtypes. This also follows convention with the rest of the framework. Minor updates to util classes All in service of changes above. See diffs for self-explanatory details. * BeanUtils * ObjectUtils * ReflectionUtils
1 parent b04987c commit b4fea47

File tree

127 files changed

+7398
-1133
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

127 files changed

+7398
-1133
lines changed

org.springframework.aop/src/main/java/org/springframework/aop/config/AopNamespaceUtils.java

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@
1616

1717
package org.springframework.aop.config;
1818

19-
import org.w3c.dom.Element;
20-
2119
import org.springframework.beans.factory.config.BeanDefinition;
2220
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
21+
import org.springframework.beans.factory.parsing.ComponentRegistrar;
2322
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
2423
import org.springframework.beans.factory.xml.ParserContext;
24+
import org.w3c.dom.Element;
2525

2626
/**
2727
* Utility class for handling registration of auto-proxy creators used internally
@@ -52,6 +52,11 @@ public abstract class AopNamespaceUtils {
5252
private static final String EXPOSE_PROXY_ATTRIBUTE = "expose-proxy";
5353

5454

55+
/**
56+
* @deprecated since Spring 3.1 in favor of
57+
* {@link #registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry, ComponentRegistrar, Object, Boolean, Boolean)}
58+
*/
59+
@Deprecated
5560
public static void registerAutoProxyCreatorIfNecessary(
5661
ParserContext parserContext, Element sourceElement) {
5762

@@ -61,6 +66,20 @@ public static void registerAutoProxyCreatorIfNecessary(
6166
registerComponentIfNecessary(beanDefinition, parserContext);
6267
}
6368

69+
public static void registerAutoProxyCreatorIfNecessary(
70+
BeanDefinitionRegistry registry, ComponentRegistrar parserContext, Object source, Boolean proxyTargetClass, Boolean exposeProxy) {
71+
72+
BeanDefinition beanDefinition =
73+
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry, source);
74+
useClassProxyingIfNecessary(registry, proxyTargetClass, exposeProxy);
75+
registerComponentIfNecessary(beanDefinition, parserContext);
76+
}
77+
78+
public static void registerAutoProxyCreatorIfNecessary(
79+
BeanDefinitionRegistry registry, ComponentRegistrar parserContext, Object source, Boolean proxyTargetClass) {
80+
registerAutoProxyCreatorIfNecessary(registry, parserContext, source, proxyTargetClass, false);
81+
}
82+
6483
public static void registerAspectJAutoProxyCreatorIfNecessary(
6584
ParserContext parserContext, Element sourceElement) {
6685

@@ -101,6 +120,12 @@ public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistr
101120
}
102121

103122

123+
/**
124+
* @deprecated since Spring 3.1 in favor of
125+
* {@link #useClassProxyingIfNecessary(BeanDefinitionRegistry, Boolean, Boolean)}
126+
* which does not require a parameter of type org.w3c.dom.Element
127+
*/
128+
@Deprecated
104129
private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, Element sourceElement) {
105130
if (sourceElement != null) {
106131
boolean proxyTargetClass = Boolean.valueOf(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
@@ -114,11 +139,20 @@ private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry,
114139
}
115140
}
116141

117-
private static void registerComponentIfNecessary(BeanDefinition beanDefinition, ParserContext parserContext) {
142+
private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, Boolean proxyTargetClass, Boolean exposeProxy) {
143+
if (proxyTargetClass) {
144+
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
145+
}
146+
if (exposeProxy) {
147+
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
148+
}
149+
}
150+
151+
private static void registerComponentIfNecessary(BeanDefinition beanDefinition, ComponentRegistrar componentRegistrar) {
118152
if (beanDefinition != null) {
119153
BeanComponentDefinition componentDefinition =
120154
new BeanComponentDefinition(beanDefinition, AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME);
121-
parserContext.registerComponent(componentDefinition);
155+
componentRegistrar.registerComponent(componentDefinition);
122156
}
123157
}
124158

org.springframework.beans/src/main/java/org/springframework/beans/BeanUtils.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ public static <T> T instantiate(Class<T> clazz) throws BeanInstantiationExceptio
8686
}
8787

8888
/**
89-
* Convenience method to instantiate a class using its no-arg constructor.
89+
* Instantiate a class using its no-arg constructor.
9090
* As this method doesn't try to load classes by name, it should avoid
9191
* class-loading issues.
9292
* <p>Note that this method tries to set the constructor accessible
@@ -108,6 +108,27 @@ public static <T> T instantiateClass(Class<T> clazz) throws BeanInstantiationExc
108108
}
109109
}
110110

111+
/**
112+
* Instantiate a class using its no-arg constructor and return the new instance
113+
* as the the specified assignable type.
114+
* <p>Useful in cases where
115+
* the type of the class to instantiate (clazz) is not available, but the type
116+
* desired (assignableTo) is known.
117+
* <p>As this method doesn't try to load classes by name, it should avoid
118+
* class-loading issues.
119+
* <p>Note that this method tries to set the constructor accessible
120+
* if given a non-accessible (that is, non-public) constructor.
121+
* @param clazz class to instantiate
122+
* @param assignableTo type that clazz must be assignableTo
123+
* @return the new instance
124+
* @throws BeanInstantiationException if the bean cannot be instantiated
125+
*/
126+
@SuppressWarnings("unchecked")
127+
public static <T> T instantiateClass(Class<?> clazz, Class<T> assignableTo) throws BeanInstantiationException {
128+
Assert.isAssignable(assignableTo, clazz);
129+
return (T)instantiateClass(clazz);
130+
}
131+
111132
/**
112133
* Convenience method to instantiate a class using the given constructor.
113134
* As this method doesn't try to load classes by name, it should avoid
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Copyright 2002-2011 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.beans.factory.parsing;
18+
19+
import org.springframework.beans.factory.config.BeanDefinition;
20+
21+
public interface BeanDefinitionRegistrar {
22+
23+
String registerWithGeneratedName(BeanDefinition beanDefinition);
24+
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright 2002-2011 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.beans.factory.parsing;
18+
19+
public interface ComponentRegistrar extends BeanDefinitionRegistrar {
20+
21+
void registerBeanComponent(BeanComponentDefinition component);
22+
23+
void registerComponent(ComponentDefinition component);
24+
}

org.springframework.beans/src/main/java/org/springframework/beans/factory/parsing/ReaderContext.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,13 @@ public class ReaderContext {
3030

3131
private final Resource resource;
3232

33-
private final ProblemReporter problemReporter;
34-
3533
private final ReaderEventListener eventListener;
3634

3735
private final SourceExtractor sourceExtractor;
3836

37+
// TODO SPR-7420: review exposing problem reporter
38+
protected final ProblemReporter problemReporter;
39+
3940

4041
public ReaderContext(Resource resource, ProblemReporter problemReporter,
4142
ReaderEventListener eventListener, SourceExtractor sourceExtractor) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright 2002-2011 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.beans.factory.parsing;
18+
19+
import java.util.ArrayList;
20+
import java.util.List;
21+
22+
import org.springframework.core.io.DescriptiveResource;
23+
24+
/**
25+
* TODO SPR-7420: document
26+
*
27+
* @author Chris Beams
28+
* @since 3.1
29+
*/
30+
public class SimpleProblemCollector {
31+
32+
private Location location = null;
33+
private List<Problem> errors = new ArrayList<Problem>();
34+
35+
public SimpleProblemCollector(Object location) {
36+
if (location != null) {
37+
this.location = new Location(new DescriptiveResource(location.toString()));
38+
}
39+
}
40+
41+
public void error(String message) {
42+
this.errors.add(new Problem(message, this.location));
43+
}
44+
45+
public void error(String message, Throwable cause) {
46+
this.errors.add(new Problem(message, this.location, null, cause));
47+
}
48+
49+
public void reportProblems(ProblemReporter reporter) {
50+
for (Problem error : errors) {
51+
reporter.error(error);
52+
}
53+
}
54+
55+
public boolean hasErrors() {
56+
return this.errors.size() > 0;
57+
}
58+
59+
}

org.springframework.beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2009 the original author or authors.
2+
* Copyright 2002-2011 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.

org.springframework.beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionReaderUtils.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ public static void registerBeanDefinition(
166166
* for the given bean definition or the definition cannot be registered
167167
*/
168168
public static String registerWithGeneratedName(
169-
AbstractBeanDefinition definition, BeanDefinitionRegistry registry)
169+
BeanDefinition definition, BeanDefinitionRegistry registry)
170170
throws BeanDefinitionStoreException {
171171

172172
String generatedName = generateBeanName(definition, registry, false);

org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/BeanDefinitionParser.java

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2010 the original author or authors.
2+
* Copyright 2002-2011 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -21,21 +21,28 @@
2121
import org.springframework.beans.factory.config.BeanDefinition;
2222

2323
/**
24-
* Interface used by the
25-
* {@link org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader} to
26-
* handle custom, top-level (directly under <code>&lt;beans&gt;</code>) tags.
24+
* Interface used by the {@link DefaultBeanDefinitionDocumentReader} to handle custom,
25+
* top-level (directly under {@code <beans>}) tags.
2726
*
2827
* <p>Implementations are free to turn the metadata in the custom tag into as many
2928
* {@link BeanDefinition BeanDefinitions} as required.
3029
*
3130
* <p>The parser locates a {@link BeanDefinitionParser} from the associated
3231
* {@link NamespaceHandler} for the namespace in which the custom tag resides.
3332
*
33+
* <p>Implementations are encouraged to decouple XML parsing from bean registration by
34+
* parsing element(s) into a {@link org.springframework.context.FeatureSpecification
35+
* FeatureSpecification} object and subsequently executing that specification.
36+
* Doing so allows for maximum reuse between XML-based and annotation-based
37+
* configuration options.
38+
*
3439
* @author Rob Harrop
3540
* @since 2.0
3641
* @see NamespaceHandler
37-
* @see org.springframework.beans.factory.xml.BeanDefinitionDecorator
3842
* @see AbstractBeanDefinitionParser
43+
* @see org.springframework.beans.factory.xml.BeanDefinitionDecorator
44+
* @see org.springframework.context.FeatureSpecification
45+
* @see org.springframework.context.AbstractSpecificationExecutor
3946
*/
4047
public interface BeanDefinitionParser {
4148

org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/ParserContext.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import org.springframework.beans.factory.config.BeanDefinition;
2222
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
2323
import org.springframework.beans.factory.parsing.ComponentDefinition;
24+
import org.springframework.beans.factory.parsing.ComponentRegistrar;
2425
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
2526
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
2627
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
@@ -36,7 +37,7 @@
3637
* @see XmlReaderContext
3738
* @see BeanDefinitionParserDelegate
3839
*/
39-
public final class ParserContext {
40+
public final class ParserContext implements ComponentRegistrar {
4041

4142
private final XmlReaderContext readerContext;
4243

@@ -121,4 +122,8 @@ public void registerBeanComponent(BeanComponentDefinition component) {
121122
registerComponent(component);
122123
}
123124

125+
public String registerWithGeneratedName(BeanDefinition beanDefinition) {
126+
return this.readerContext.registerWithGeneratedName(beanDefinition);
127+
}
128+
124129
}

0 commit comments

Comments
 (0)