Skip to content

Commit 9cc1255

Browse files
committed
Fix STS compatibility issues; other improvements
Revert changes to ParserContext, ReaderContext, and XmlReaderContext These changes cause cross-version incompatibilities at tooling time -- for instance, an STS version that ships with Spring 3.0.5 classloads the ParserContext defined in that version, whereas it classloads NamespaceHandlers and BeanDefinitionParsers (by default) from the user application classpath, which may be building against 3.1.0. If so, the changes introduced to these types in 3.1.0 are incompatible with expectations in the 3.0.5 world and cause all manner of problems. In this case, it was NoSuchMethodError due to the newly-added XmlReaderContext.getProblemReporter() method; also IncompatibleClassChangeError due to the introduction of the ComponentRegistrar interface on ParserContext. Each of these problems have been mitigated, though the solutions are not ideal. The method mentioned has been removed, and instead the problemReporter field is now accessed reflectively. ParserContext now no longer implements ComponentRegistrar, and rather a ComponentRegistrarAdapter class has been introduced that passes method calls through to a ParserContext delegate. Introduce AbstractSpecificationBeanDefinitionParser AbstractSpecificationBeanDefinitionParser has been introduced in order to improve the programming model for BeanDefinitionParsers that have been refactored to the new FeatureSpecification model. This new base class and it's template method implementation of parse/doParse ensure that common concerns like (1) adapting a ParserContext into a SpecificationContext, (2) setting source and source name on the specification, and (3) actually executing the specification are all managed by the base class. The subclass implementation of doParse need only actually parse XML, populate and return the FeatureSpecification object. This change removed the many duplicate 'createSpecificationContext' methods that had been lingering. Minor improvement to BeanDefinitionReaderUtils API Introduced new BeanDefinitionReaderUtils#registerWithGeneratedName variant that accepts BeanDefinition as opposed to AbstractBeanDefinition, as BeanDefinition is all that is actually necessary to satisfy the needs of the method implementation. The latter variant accepting AbstractBeanDefinition has been deprecated but remains intact and delegates to the new variant in order to maintain binary compatibility.
1 parent 939da34 commit 9cc1255

File tree

20 files changed

+214
-227
lines changed

20 files changed

+214
-227
lines changed

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.springframework.beans.factory.config.BeanDefinition;
2020
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
2121
import org.springframework.beans.factory.parsing.ComponentRegistrar;
22+
import org.springframework.beans.factory.parsing.ComponentRegistrarAdapter;
2223
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
2324
import org.springframework.beans.factory.xml.ParserContext;
2425
import org.w3c.dom.Element;
@@ -63,7 +64,7 @@ public static void registerAutoProxyCreatorIfNecessary(
6364
BeanDefinition beanDefinition = AopConfigUtils.registerAutoProxyCreatorIfNecessary(
6465
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
6566
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
66-
registerComponentIfNecessary(beanDefinition, parserContext);
67+
registerComponentIfNecessary(beanDefinition, new ComponentRegistrarAdapter(parserContext));
6768
}
6869

6970
public static void registerAutoProxyCreatorIfNecessary(
@@ -86,7 +87,7 @@ public static void registerAspectJAutoProxyCreatorIfNecessary(
8687
BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(
8788
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
8889
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
89-
registerComponentIfNecessary(beanDefinition, parserContext);
90+
registerComponentIfNecessary(beanDefinition, new ComponentRegistrarAdapter(parserContext));
9091
}
9192

9293
public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
@@ -95,7 +96,7 @@ public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
9596
BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
9697
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
9798
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
98-
registerComponentIfNecessary(beanDefinition, parserContext);
99+
registerComponentIfNecessary(beanDefinition, new ComponentRegistrarAdapter(parserContext));
99100
}
100101

101102
/**
@@ -107,7 +108,7 @@ public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
107108
public static void registerAutoProxyCreatorIfNecessary(ParserContext parserContext, Object source) {
108109
BeanDefinition beanDefinition = AopConfigUtils.registerAutoProxyCreatorIfNecessary(
109110
parserContext.getRegistry(), source);
110-
registerComponentIfNecessary(beanDefinition, parserContext);
111+
registerComponentIfNecessary(beanDefinition, new ComponentRegistrarAdapter(parserContext));
111112
}
112113

113114
/**

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

Lines changed: 0 additions & 25 deletions
This file was deleted.

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,20 @@
1616

1717
package org.springframework.beans.factory.parsing;
1818

19-
public interface ComponentRegistrar extends BeanDefinitionRegistrar {
19+
import org.springframework.beans.factory.config.BeanDefinition;
20+
21+
/**
22+
* TODO SPR-7420: document
23+
*
24+
* @author Chris Beams
25+
* @since 3.1
26+
*/
27+
public interface ComponentRegistrar {
28+
29+
String registerWithGeneratedName(BeanDefinition beanDefinition);
2030

2131
void registerBeanComponent(BeanComponentDefinition component);
2232

2333
void registerComponent(ComponentDefinition component);
34+
2435
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
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+
import org.springframework.beans.factory.xml.ParserContext;
21+
22+
/**
23+
* TODO SPR-7420: document
24+
* <p>Adapter is necessary as opposed to having ParserContext
25+
* implement ComponentRegistrar directly due to tooling issues.
26+
* STS may ship with a version of Spring older that 3.1 (when
27+
* this type was introduced), and will run into
28+
* IncompatibleClassChangeErrors when it's (3.0.5) ParserContext
29+
* tries to mix with our (3.1.0) BeanDefinitionParser
30+
* (and related) infrastructure.
31+
*
32+
* @author Chris Beams
33+
* @since 3.1
34+
*/
35+
public class ComponentRegistrarAdapter implements ComponentRegistrar {
36+
37+
private final ParserContext parserContext;
38+
39+
public ComponentRegistrarAdapter(ParserContext parserContext) {
40+
this.parserContext = parserContext;
41+
}
42+
43+
public String registerWithGeneratedName(BeanDefinition beanDefinition) {
44+
return this.parserContext.getReaderContext().registerWithGeneratedName(beanDefinition);
45+
}
46+
47+
public void registerBeanComponent(BeanComponentDefinition component) {
48+
this.parserContext.registerBeanComponent(component);
49+
}
50+
51+
public void registerComponent(ComponentDefinition component) {
52+
this.parserContext.registerComponent(component);
53+
}
54+
55+
}

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

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

3131
private final Resource resource;
3232

33+
private final ProblemReporter problemReporter;
34+
3335
private final ReaderEventListener eventListener;
3436

3537
private final SourceExtractor sourceExtractor;
3638

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

4140
public ReaderContext(Resource resource, ProblemReporter problemReporter,
4241
ReaderEventListener eventListener, SourceExtractor sourceExtractor) {

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

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,12 +166,24 @@ 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 {
171-
172171
String generatedName = generateBeanName(definition, registry, false);
173172
registry.registerBeanDefinition(generatedName, definition);
174173
return generatedName;
175174
}
176175

176+
/**
177+
* @deprecated since Spring 3.1 in favor of
178+
* {@link #registerWithGeneratedName(BeanDefinition, BeanDefinitionRegistry)}
179+
* and its more general signature.
180+
*/
181+
@Deprecated
182+
public static String registerWithGeneratedName(
183+
AbstractBeanDefinition definition, BeanDefinitionRegistry registry)
184+
throws BeanDefinitionStoreException {
185+
return registerWithGeneratedName((BeanDefinition)definition, registry);
186+
187+
}
188+
177189
}

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

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
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;
2524
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
2625
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
2726
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
@@ -37,7 +36,7 @@
3736
* @see XmlReaderContext
3837
* @see BeanDefinitionParserDelegate
3938
*/
40-
public final class ParserContext implements ComponentRegistrar {
39+
public final class ParserContext {
4140

4241
private final XmlReaderContext readerContext;
4342

@@ -122,8 +121,4 @@ public void registerBeanComponent(BeanComponentDefinition component) {
122121
registerComponent(component);
123122
}
124123

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

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

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,4 @@ public String registerWithGeneratedName(BeanDefinition beanDefinition) {
8383
return generatedName;
8484
}
8585

86-
// TODO SPR-7420: review exposing problem reporter
87-
public ProblemReporter getProblemReporter() {
88-
return this.problemReporter;
89-
}
90-
9186
}

org.springframework.context/src/main/java/org/springframework/context/annotation/ComponentScanBeanDefinitionParser.java

Lines changed: 9 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,9 @@
1616

1717
package org.springframework.context.annotation;
1818

19-
import org.springframework.beans.factory.config.BeanDefinition;
20-
import org.springframework.beans.factory.xml.BeanDefinitionParser;
2119
import org.springframework.beans.factory.xml.ParserContext;
22-
import org.springframework.beans.factory.xml.XmlReaderContext;
23-
import org.springframework.context.config.SpecificationContext;
20+
import org.springframework.context.config.AbstractSpecificationBeanDefinitionParser;
21+
import org.springframework.context.config.FeatureSpecification;
2422
import org.w3c.dom.Element;
2523
import org.w3c.dom.Node;
2624
import org.w3c.dom.NodeList;
@@ -38,11 +36,10 @@
3836
* @see ComponentScanSpec
3937
* @see ComponentScanExecutor
4038
*/
41-
public class ComponentScanBeanDefinitionParser implements BeanDefinitionParser {
39+
public class ComponentScanBeanDefinitionParser extends AbstractSpecificationBeanDefinitionParser {
4240

43-
public BeanDefinition parse(Element element, ParserContext parserContext) {
44-
XmlReaderContext readerContext = parserContext.getReaderContext();
45-
ClassLoader classLoader = readerContext.getResourceLoader().getClassLoader();
41+
public FeatureSpecification doParse(Element element, ParserContext parserContext) {
42+
ClassLoader classLoader = parserContext.getReaderContext().getResourceLoader().getClassLoader();
4643

4744
ComponentScanSpec spec =
4845
ComponentScanSpec.forDelimitedPackages(element.getAttribute("base-package"))
@@ -51,7 +48,9 @@ public BeanDefinition parse(Element element, ParserContext parserContext) {
5148
.resourcePattern(element.getAttribute("resource-pattern"))
5249
.beanNameGenerator(element.getAttribute("name-generator"), classLoader)
5350
.scopeMetadataResolver(element.getAttribute("scope-resolver"), classLoader)
54-
.scopedProxyMode(element.getAttribute("scoped-proxy"));
51+
.scopedProxyMode(element.getAttribute("scoped-proxy"))
52+
.beanDefinitionDefaults(parserContext.getDelegate().getBeanDefinitionDefaults())
53+
.autowireCandidatePatterns(parserContext.getDelegate().getAutowireCandidatePatterns());
5554

5655
// Parse exclude and include filter elements.
5756
NodeList nodeList = element.getChildNodes();
@@ -70,26 +69,7 @@ else if ("exclude-filter".equals(localName)) {
7069
}
7170
}
7271

73-
spec.beanDefinitionDefaults(parserContext.getDelegate().getBeanDefinitionDefaults())
74-
.autowireCandidatePatterns(parserContext.getDelegate().getAutowireCandidatePatterns())
75-
.source(readerContext.extractSource(element))
76-
.sourceName(element.getTagName())
77-
.execute(createSpecificationContext(parserContext));
78-
return null;
79-
}
80-
81-
82-
// Adapt the given ParserContext instance into an SpecificationContext.
83-
// TODO SPR-7420: create a common ParserContext-to-SpecificationContext adapter utility
84-
// or otherwise unify these two types
85-
private SpecificationContext createSpecificationContext(ParserContext parserContext) {
86-
SpecificationContext specificationContext = new SpecificationContext();
87-
specificationContext.setRegistry(parserContext.getRegistry());
88-
specificationContext.setRegistrar(parserContext);
89-
specificationContext.setResourceLoader(parserContext.getReaderContext().getResourceLoader());
90-
specificationContext.setEnvironment(parserContext.getDelegate().getEnvironment());
91-
specificationContext.setProblemReporter(parserContext.getReaderContext().getProblemReporter());
92-
return specificationContext;
72+
return spec;
9373
}
9474

9575
}

org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ public ConfigurationClassBeanDefinitionReader(final BeanDefinitionRegistry regis
107107
this.sourceExtractor = sourceExtractor;
108108
this.problemReporter = problemReporter;
109109
this.metadataReaderFactory = metadataReaderFactory;
110+
// TODO SPR-7420: see about passing in the SpecificationContext created in ConfigurationClassPostProcessor
110111
this.specificationContext = new SpecificationContext();
111112
this.specificationContext.setRegistry(this.registry);
112113
this.specificationContext.setRegistrar(new SimpleComponentRegistrar(this.registry));
@@ -171,7 +172,7 @@ private void doLoadBeanDefinitionForConfigurationClassIfNecessary(ConfigurationC
171172
}
172173

173174
// no bean definition exists yet -> this must be an imported configuration class (@Import).
174-
GenericBeanDefinition configBeanDef = new GenericBeanDefinition();
175+
BeanDefinition configBeanDef = new GenericBeanDefinition();
175176
String className = configClass.getMetadata().getClassName();
176177
configBeanDef.setBeanClassName(className);
177178
if (checkConfigurationClassCandidate(configBeanDef, this.metadataReaderFactory)) {

0 commit comments

Comments
 (0)