From c89202870520fd7ffb9969318ad74ffd25dc8c00 Mon Sep 17 00:00:00 2001 From: Chris Beams Date: Fri, 6 May 2011 19:03:52 +0000 Subject: [PATCH] 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 git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@4255 50f2f4bb-b051-0410-bef5-90022cba6387 --- .../resources/changelog.txt | 2 + .../aop/config/AopNamespaceUtils.java | 49 +- .../factory/parsing/ComponentRegistrar.java | 35 -- .../parsing/ComponentRegistrarAdapter.java | 55 --- .../factory/parsing/ProblemCollector.java | 35 -- .../parsing/SimpleProblemCollector.java | 59 --- .../factory/xml/BeanDefinitionParser.java | 18 +- org.springframework.context/.springBeans | 3 +- .../context/annotation/BeanMethod.java | 34 +- .../ComponentScanAnnotationParser.java | 97 ---- .../ComponentScanBeanDefinitionParser.java | 263 ++++++++-- .../annotation/ComponentScanExecutor.java | 110 ----- .../context/annotation/ComponentScanSpec.java | 460 ------------------ ...onfigurationClassBeanDefinitionReader.java | 43 +- .../ConfigurationClassEnhancer.java | 5 +- .../ConfigurationClassPostProcessor.java | 190 +------- .../annotation/ConfigurationMethod.java | 60 +++ .../annotation/EarlyBeanReferenceProxy.java | 30 -- .../EarlyBeanReferenceProxyCreator.java | 254 ---------- .../context/annotation/Feature.java | 34 -- .../context/annotation/FeatureAnnotation.java | 45 -- .../annotation/FeatureAnnotationParser.java | 61 --- .../annotation/FeatureConfiguration.java | 54 -- .../FeatureMethodExecutionException.java | 28 -- .../annotation/ProxyCreationException.java | 26 - .../annotation/SimpleComponentRegistrar.java | 52 -- .../config/AbstractFeatureSpecification.java | 78 --- ...ractSpecificationBeanDefinitionParser.java | 83 ---- .../config/AbstractSpecificationExecutor.java | 54 -- .../context/config/FeatureSpecification.java | 127 ----- .../config/FeatureSpecificationExecutor.java | 41 -- .../config/SourceAwareSpecification.java | 35 -- .../context/config/SpecificationContext.java | 81 --- ...FactoryAwareFeatureConfigurationTests.java | 67 --- .../ComponentScanExecutorTests.java | 67 --- .../annotation/ComponentScanFeatureTests.java | 55 --- .../annotation/ComponentScanSpecTests.java | 411 ---------------- .../EarlyBeanReferenceProxyCreatorTests.java | 312 ------------ .../FeatureConfigurationClassTests.java | 83 ---- ...nfigurationImportResourceTests-context.xml | 10 - ...atureConfigurationImportResourceTests.java | 69 --- .../FeatureConfigurationImportTests.java | 105 ---- .../FeatureMethodBeanReferenceTests.java | 76 --- .../FeatureMethodEarlyBeanProxyTests.java | 192 -------- .../annotation/FeatureMethodErrorTests.java | 113 ----- ...tureMethodQualifiedBeanReferenceTests.java | 70 --- .../FeatureMethodValueInjectionTests.java | 135 ----- .../SimpleFeatureMethodProcessingTests.java | 64 --- .../FeatureMethodAndAutowiredFieldTests.xml | 8 - .../FeatureMethodLifecycleIssueTestSuite.java | 37 -- .../configuration/StubSpecification.java | 46 -- .../context/annotation/FeatureTestSuite.java | 80 --- .../AnnotationDrivenBeanDefinitionParser.java | 10 +- ...ransactionManagerBeanDefinitionParser.java | 6 +- .../config/TxAdviceBeanDefinitionParser.java | 4 +- .../config/TxAnnotationDriven.java | 198 -------- .../config/TxAnnotationDrivenExecutor.java | 139 ------ .../config/TxNamespaceHandler.java | 11 + .../TxAnnotationDrivenFeatureTests.java | 147 ------ ...ttpRequestHandlerBeanDefinitionParser.java | 57 +++ .../AnnotationDrivenBeanDefinitionParser.java | 273 +++++++++-- ...ultServletHandlerBeanDefinitionParser.java | 52 +- .../InterceptorsBeanDefinitionParser.java | 59 ++- .../servlet/config/MvcAnnotationDriven.java | 259 ---------- .../config/MvcAnnotationDrivenExecutor.java | 236 --------- .../config/MvcDefaultServletHandler.java | 91 ---- .../MvcDefaultServletHandlerExecutor.java | 82 ---- .../web/servlet/config/MvcInterceptors.java | 158 ------ .../config/MvcInterceptorsExecutor.java | 60 --- .../web/servlet/config/MvcResources.java | 179 ------- .../servlet/config/MvcResourcesExecutor.java | 85 ---- .../servlet/config/MvcViewControllers.java | 90 ---- .../config/MvcViewControllersExecutor.java | 89 ---- .../config/ResourcesBeanDefinitionParser.java | 97 +++- .../ViewControllerBeanDefinitionParser.java | 88 +++- .../MvcAnnotationDrivenFeatureTests.java | 107 ---- .../config/MvcDefaultServletHandlerTests.java | 61 --- .../servlet/config/MvcInterceptorsTests.java | 126 ----- .../web/servlet/config/MvcResourcesTests.java | 98 ---- .../config/MvcViewControllersTests.java | 131 ----- 80 files changed, 857 insertions(+), 6737 deletions(-) delete mode 100644 org.springframework.beans/src/main/java/org/springframework/beans/factory/parsing/ComponentRegistrar.java delete mode 100644 org.springframework.beans/src/main/java/org/springframework/beans/factory/parsing/ComponentRegistrarAdapter.java delete mode 100644 org.springframework.beans/src/main/java/org/springframework/beans/factory/parsing/ProblemCollector.java delete mode 100644 org.springframework.beans/src/main/java/org/springframework/beans/factory/parsing/SimpleProblemCollector.java delete mode 100644 org.springframework.context/src/main/java/org/springframework/context/annotation/ComponentScanAnnotationParser.java delete mode 100644 org.springframework.context/src/main/java/org/springframework/context/annotation/ComponentScanExecutor.java delete mode 100644 org.springframework.context/src/main/java/org/springframework/context/annotation/ComponentScanSpec.java create mode 100644 org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationMethod.java delete mode 100644 org.springframework.context/src/main/java/org/springframework/context/annotation/EarlyBeanReferenceProxy.java delete mode 100644 org.springframework.context/src/main/java/org/springframework/context/annotation/EarlyBeanReferenceProxyCreator.java delete mode 100644 org.springframework.context/src/main/java/org/springframework/context/annotation/Feature.java delete mode 100644 org.springframework.context/src/main/java/org/springframework/context/annotation/FeatureAnnotation.java delete mode 100644 org.springframework.context/src/main/java/org/springframework/context/annotation/FeatureAnnotationParser.java delete mode 100644 org.springframework.context/src/main/java/org/springframework/context/annotation/FeatureConfiguration.java delete mode 100644 org.springframework.context/src/main/java/org/springframework/context/annotation/FeatureMethodExecutionException.java delete mode 100644 org.springframework.context/src/main/java/org/springframework/context/annotation/ProxyCreationException.java delete mode 100644 org.springframework.context/src/main/java/org/springframework/context/annotation/SimpleComponentRegistrar.java delete mode 100644 org.springframework.context/src/main/java/org/springframework/context/config/AbstractFeatureSpecification.java delete mode 100644 org.springframework.context/src/main/java/org/springframework/context/config/AbstractSpecificationBeanDefinitionParser.java delete mode 100644 org.springframework.context/src/main/java/org/springframework/context/config/AbstractSpecificationExecutor.java delete mode 100644 org.springframework.context/src/main/java/org/springframework/context/config/FeatureSpecification.java delete mode 100644 org.springframework.context/src/main/java/org/springframework/context/config/FeatureSpecificationExecutor.java delete mode 100644 org.springframework.context/src/main/java/org/springframework/context/config/SourceAwareSpecification.java delete mode 100644 org.springframework.context/src/main/java/org/springframework/context/config/SpecificationContext.java delete mode 100644 org.springframework.context/src/test/java/org/springframework/context/annotation/BeanFactoryAwareFeatureConfigurationTests.java delete mode 100644 org.springframework.context/src/test/java/org/springframework/context/annotation/ComponentScanExecutorTests.java delete mode 100644 org.springframework.context/src/test/java/org/springframework/context/annotation/ComponentScanFeatureTests.java delete mode 100644 org.springframework.context/src/test/java/org/springframework/context/annotation/ComponentScanSpecTests.java delete mode 100644 org.springframework.context/src/test/java/org/springframework/context/annotation/EarlyBeanReferenceProxyCreatorTests.java delete mode 100644 org.springframework.context/src/test/java/org/springframework/context/annotation/FeatureConfigurationClassTests.java delete mode 100644 org.springframework.context/src/test/java/org/springframework/context/annotation/FeatureConfigurationImportResourceTests-context.xml delete mode 100644 org.springframework.context/src/test/java/org/springframework/context/annotation/FeatureConfigurationImportResourceTests.java delete mode 100644 org.springframework.context/src/test/java/org/springframework/context/annotation/FeatureConfigurationImportTests.java delete mode 100644 org.springframework.context/src/test/java/org/springframework/context/annotation/FeatureMethodBeanReferenceTests.java delete mode 100644 org.springframework.context/src/test/java/org/springframework/context/annotation/FeatureMethodEarlyBeanProxyTests.java delete mode 100644 org.springframework.context/src/test/java/org/springframework/context/annotation/FeatureMethodErrorTests.java delete mode 100644 org.springframework.context/src/test/java/org/springframework/context/annotation/FeatureMethodQualifiedBeanReferenceTests.java delete mode 100644 org.springframework.context/src/test/java/org/springframework/context/annotation/FeatureMethodValueInjectionTests.java delete mode 100644 org.springframework.context/src/test/java/org/springframework/context/annotation/SimpleFeatureMethodProcessingTests.java delete mode 100644 org.springframework.context/src/test/java/org/springframework/context/annotation/configuration/FeatureMethodAndAutowiredFieldTests.xml delete mode 100644 org.springframework.context/src/test/java/org/springframework/context/annotation/configuration/FeatureMethodLifecycleIssueTestSuite.java delete mode 100644 org.springframework.context/src/test/java/org/springframework/context/annotation/configuration/StubSpecification.java delete mode 100644 org.springframework.integration-tests/src/test/java/org/springframework/context/annotation/FeatureTestSuite.java delete mode 100644 org.springframework.transaction/src/main/java/org/springframework/transaction/config/TxAnnotationDriven.java delete mode 100644 org.springframework.transaction/src/main/java/org/springframework/transaction/config/TxAnnotationDrivenExecutor.java delete mode 100644 org.springframework.transaction/src/test/java/org/springframework/transaction/annotation/TxAnnotationDrivenFeatureTests.java create mode 100644 org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/AbstractHttpRequestHandlerBeanDefinitionParser.java delete mode 100644 org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcAnnotationDriven.java delete mode 100644 org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcAnnotationDrivenExecutor.java delete mode 100644 org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcDefaultServletHandler.java delete mode 100644 org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcDefaultServletHandlerExecutor.java delete mode 100644 org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcInterceptors.java delete mode 100644 org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcInterceptorsExecutor.java delete mode 100644 org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcResources.java delete mode 100644 org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcResourcesExecutor.java delete mode 100644 org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcViewControllers.java delete mode 100644 org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcViewControllersExecutor.java delete mode 100644 org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcAnnotationDrivenFeatureTests.java delete mode 100644 org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcDefaultServletHandlerTests.java delete mode 100644 org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcInterceptorsTests.java delete mode 100644 org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcResourcesTests.java delete mode 100644 org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcViewControllersTests.java diff --git a/build-spring-framework/resources/changelog.txt b/build-spring-framework/resources/changelog.txt index b8a2b9b768d..6636c9503e8 100644 --- a/build-spring-framework/resources/changelog.txt +++ b/build-spring-framework/resources/changelog.txt @@ -7,6 +7,8 @@ Changes in version 3.1 M2 (2011-??-??) -------------------------------------- * deprecated AbstractJUnit38SpringContextTests and AbstractTransactionalJUnit38SpringContextTests +* eliminated @Feature support in favor of @Enable* and framework-provided @Configuration classes +* introduced @EnableTransactionManagement, @EnableScheduling, and other @Enable* annotations Changes in version 3.1 M1 (2011-02-11) diff --git a/org.springframework.aop/src/main/java/org/springframework/aop/config/AopNamespaceUtils.java b/org.springframework.aop/src/main/java/org/springframework/aop/config/AopNamespaceUtils.java index a21999ff776..ae9888dca4d 100644 --- a/org.springframework.aop/src/main/java/org/springframework/aop/config/AopNamespaceUtils.java +++ b/org.springframework.aop/src/main/java/org/springframework/aop/config/AopNamespaceUtils.java @@ -16,13 +16,12 @@ package org.springframework.aop.config; +import org.w3c.dom.Element; + import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.parsing.BeanComponentDefinition; -import org.springframework.beans.factory.parsing.ComponentRegistrar; -import org.springframework.beans.factory.parsing.ComponentRegistrarAdapter; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.xml.ParserContext; -import org.w3c.dom.Element; /** * Utility class for handling registration of auto-proxy creators used internally @@ -53,41 +52,22 @@ public abstract class AopNamespaceUtils { private static final String EXPOSE_PROXY_ATTRIBUTE = "expose-proxy"; - /** - * @deprecated since Spring 3.1 in favor of - * {@link #registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry, ComponentRegistrar, Object, Boolean, Boolean)} - */ - @Deprecated public static void registerAutoProxyCreatorIfNecessary( ParserContext parserContext, Element sourceElement) { BeanDefinition beanDefinition = AopConfigUtils.registerAutoProxyCreatorIfNecessary( parserContext.getRegistry(), parserContext.extractSource(sourceElement)); useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement); - registerComponentIfNecessary(beanDefinition, new ComponentRegistrarAdapter(parserContext)); - } - - public static void registerAutoProxyCreatorIfNecessary( - BeanDefinitionRegistry registry, ComponentRegistrar parserContext, Object source, Boolean proxyTargetClass, Boolean exposeProxy) { - - BeanDefinition beanDefinition = - AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry, source); - useClassProxyingIfNecessary(registry, proxyTargetClass, exposeProxy); registerComponentIfNecessary(beanDefinition, parserContext); } - public static void registerAutoProxyCreatorIfNecessary( - BeanDefinitionRegistry registry, ComponentRegistrar parserContext, Object source, Boolean proxyTargetClass) { - registerAutoProxyCreatorIfNecessary(registry, parserContext, source, proxyTargetClass, false); - } - public static void registerAspectJAutoProxyCreatorIfNecessary( ParserContext parserContext, Element sourceElement) { BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary( parserContext.getRegistry(), parserContext.extractSource(sourceElement)); useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement); - registerComponentIfNecessary(beanDefinition, new ComponentRegistrarAdapter(parserContext)); + registerComponentIfNecessary(beanDefinition, parserContext); } public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary( @@ -96,7 +76,7 @@ public abstract class AopNamespaceUtils { BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary( parserContext.getRegistry(), parserContext.extractSource(sourceElement)); useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement); - registerComponentIfNecessary(beanDefinition, new ComponentRegistrarAdapter(parserContext)); + registerComponentIfNecessary(beanDefinition, parserContext); } /** @@ -108,7 +88,7 @@ public abstract class AopNamespaceUtils { public static void registerAutoProxyCreatorIfNecessary(ParserContext parserContext, Object source) { BeanDefinition beanDefinition = AopConfigUtils.registerAutoProxyCreatorIfNecessary( parserContext.getRegistry(), source); - registerComponentIfNecessary(beanDefinition, new ComponentRegistrarAdapter(parserContext)); + registerComponentIfNecessary(beanDefinition, parserContext); } /** @@ -121,12 +101,6 @@ public abstract class AopNamespaceUtils { } - /** - * @deprecated since Spring 3.1 in favor of - * {@link #useClassProxyingIfNecessary(BeanDefinitionRegistry, Boolean, Boolean)} - * which does not require a parameter of type org.w3c.dom.Element - */ - @Deprecated private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, Element sourceElement) { if (sourceElement != null) { boolean proxyTargetClass = Boolean.valueOf(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE)); @@ -140,20 +114,11 @@ public abstract class AopNamespaceUtils { } } - private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, Boolean proxyTargetClass, Boolean exposeProxy) { - if (proxyTargetClass) { - AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); - } - if (exposeProxy) { - AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); - } - } - - private static void registerComponentIfNecessary(BeanDefinition beanDefinition, ComponentRegistrar componentRegistrar) { + private static void registerComponentIfNecessary(BeanDefinition beanDefinition, ParserContext parserContext) { if (beanDefinition != null) { BeanComponentDefinition componentDefinition = new BeanComponentDefinition(beanDefinition, AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME); - componentRegistrar.registerComponent(componentDefinition); + parserContext.registerComponent(componentDefinition); } } diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/parsing/ComponentRegistrar.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/parsing/ComponentRegistrar.java deleted file mode 100644 index 45016231d71..00000000000 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/parsing/ComponentRegistrar.java +++ /dev/null @@ -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.beans.factory.parsing; - -import org.springframework.beans.factory.config.BeanDefinition; - -/** - * TODO SPR-7420: document - * - * @author Chris Beams - * @since 3.1 - */ -public interface ComponentRegistrar { - - String registerWithGeneratedName(BeanDefinition beanDefinition); - - void registerBeanComponent(BeanComponentDefinition component); - - void registerComponent(ComponentDefinition component); - -} diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/parsing/ComponentRegistrarAdapter.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/parsing/ComponentRegistrarAdapter.java deleted file mode 100644 index 36a84706f6a..00000000000 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/parsing/ComponentRegistrarAdapter.java +++ /dev/null @@ -1,55 +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.beans.factory.parsing; - -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.xml.ParserContext; - -/** - * TODO SPR-7420: document - *

Adapter is necessary as opposed to having ParserContext - * implement ComponentRegistrar directly due to tooling issues. - * STS may ship with a version of Spring older that 3.1 (when - * this type was introduced), and will run into - * IncompatibleClassChangeErrors when it's (3.0.5) ParserContext - * tries to mix with our (3.1.0) BeanDefinitionParser - * (and related) infrastructure. - * - * @author Chris Beams - * @since 3.1 - */ -public class ComponentRegistrarAdapter implements ComponentRegistrar { - - private final ParserContext parserContext; - - public ComponentRegistrarAdapter(ParserContext parserContext) { - this.parserContext = parserContext; - } - - public String registerWithGeneratedName(BeanDefinition beanDefinition) { - return this.parserContext.getReaderContext().registerWithGeneratedName(beanDefinition); - } - - public void registerBeanComponent(BeanComponentDefinition component) { - this.parserContext.registerBeanComponent(component); - } - - public void registerComponent(ComponentDefinition component) { - this.parserContext.registerComponent(component); - } - -} diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/parsing/ProblemCollector.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/parsing/ProblemCollector.java deleted file mode 100644 index f6f9d5717b7..00000000000 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/parsing/ProblemCollector.java +++ /dev/null @@ -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.beans.factory.parsing; - -/** - * TODO SPR-7420: document - * - * @author Chris Beams - * @since 3.1 - */ -public interface ProblemCollector { - - void error(String message); - - void error(String message, Throwable cause); - - void reportProblems(ProblemReporter reporter); - - boolean hasErrors(); - -} diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/parsing/SimpleProblemCollector.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/parsing/SimpleProblemCollector.java deleted file mode 100644 index bb0c9bb12d1..00000000000 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/parsing/SimpleProblemCollector.java +++ /dev/null @@ -1,59 +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.beans.factory.parsing; - -import java.util.ArrayList; -import java.util.List; - -import org.springframework.core.io.DescriptiveResource; - -/** - * TODO SPR-7420: document - * - * @author Chris Beams - * @since 3.1 - */ -public class SimpleProblemCollector implements ProblemCollector { - - private Location location = null; - private List errors = new ArrayList(); - - public SimpleProblemCollector(Object location) { - if (location != null) { - this.location = new Location(new DescriptiveResource(location.toString())); - } - } - - public void error(String message) { - this.errors.add(new Problem(message, this.location)); - } - - public void error(String message, Throwable cause) { - this.errors.add(new Problem(message, this.location, null, cause)); - } - - public void reportProblems(ProblemReporter reporter) { - for (Problem error : errors) { - reporter.error(error); - } - } - - public boolean hasErrors() { - return this.errors.size() > 0; - } - -} diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/BeanDefinitionParser.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/BeanDefinitionParser.java index 2f352d9dddf..2c92ecd4775 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/BeanDefinitionParser.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/BeanDefinitionParser.java @@ -22,7 +22,7 @@ import org.springframework.beans.factory.config.BeanDefinition; /** * Interface used by the {@link DefaultBeanDefinitionDocumentReader} to handle custom, - * top-level (directly under {@code }) tags. + * top-level (directly under {@code }) tags. * *

Implementations are free to turn the metadata in the custom tag into as many * {@link BeanDefinition BeanDefinitions} as required. @@ -30,19 +30,10 @@ import org.springframework.beans.factory.config.BeanDefinition; *

The parser locates a {@link BeanDefinitionParser} from the associated * {@link NamespaceHandler} for the namespace in which the custom tag resides. * - *

Implementations are encouraged to decouple XML parsing from bean registration by - * parsing element(s) into a {@link org.springframework.context.FeatureSpecification - * FeatureSpecification} object and subsequently executing that specification. - * Doing so allows for maximum reuse between XML-based and annotation-based - * configuration options. - * * @author Rob Harrop * @since 2.0 * @see NamespaceHandler * @see AbstractBeanDefinitionParser - * @see org.springframework.beans.factory.xml.BeanDefinitionDecorator - * @see org.springframework.context.FeatureSpecification - * @see org.springframework.context.AbstractSpecificationExecutor */ public interface BeanDefinitionParser { @@ -53,12 +44,11 @@ public interface BeanDefinitionParser { * embedded in the supplied {@link ParserContext}. *

Implementations must return the primary {@link BeanDefinition} that results * from the parse if they will ever be used in a nested fashion (for example as - * an inner tag in a <property/> tag). Implementations may return - * null if they will not be used in a nested fashion. + * an inner tag in a {@code } tag). Implementations may return + * {@code null} if they will not be used in a nested fashion. * @param element the element that is to be parsed into one or more {@link BeanDefinition BeanDefinitions} * @param parserContext the object encapsulating the current state of the parsing process; - * provides access to a {@link org.springframework.beans.factory.support.BeanDefinitionRegistry - * BeanDefinitionRegistry}. + * provides access to a {@link org.springframework.beans.factory.support.BeanDefinitionRegistry} * @return the primary {@link BeanDefinition} */ BeanDefinition parse(Element element, ParserContext parserContext); diff --git a/org.springframework.context/.springBeans b/org.springframework.context/.springBeans index c36c1e5de08..f55953e36ee 100644 --- a/org.springframework.context/.springBeans +++ b/org.springframework.context/.springBeans @@ -1,7 +1,7 @@ 1 - + @@ -11,7 +11,6 @@ src/test/java/org/springframework/context/annotation/configuration/SecondLevelSubConfig-context.xml src/test/java/org/springframework/context/annotation/configuration/ImportXmlWithAopNamespace-context.xml src/test/java/org/springframework/context/annotation/Spr6602Tests-context.xml - src/test/java/org/springframework/context/annotation/FeatureConfigurationImportResourceTests-context.xml diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/BeanMethod.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/BeanMethod.java index 477d69c5b4f..4b5d762d1d5 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/BeanMethod.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/BeanMethod.java @@ -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. */ diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/ComponentScanAnnotationParser.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/ComponentScanAnnotationParser.java deleted file mode 100644 index 47c1abedaa9..00000000000 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/ComponentScanAnnotationParser.java +++ /dev/null @@ -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 } XML element. - * - *

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 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; - } - -} diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/ComponentScanBeanDefinitionParser.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/ComponentScanBeanDefinitionParser.java index a10f608053f..2f6d1107fdf 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/ComponentScanBeanDefinitionParser.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/ComponentScanBeanDefinitionParser.java @@ -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 } element. Parsed metadata is - * used to populate and execute a {@link ComponentScanSpec} instance. + * Parser for the {@code } 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 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 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 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 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) 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; } } diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/ComponentScanExecutor.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/ComponentScanExecutor.java deleted file mode 100644 index 8570f00cd88..00000000000 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/ComponentScanExecutor.java +++ /dev/null @@ -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 { - - /** - * 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 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 processorDefinitions = - AnnotationConfigUtils.registerAnnotationConfigProcessors(registry, source); - for (BeanDefinitionHolder processorDefinition : processorDefinitions) { - compositeDef.addNestedComponent(new BeanComponentDefinition(processorDefinition)); - } - } - - specificationContext.getRegistrar().registerComponent(compositeDef); - } - -} diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/ComponentScanSpec.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/ComponentScanSpec.java deleted file mode 100644 index 13b757ba95f..00000000000 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/ComponentScanSpec.java +++ /dev/null @@ -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 component-scanning 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 EXECUTOR_TYPE = ComponentScanExecutor.class; - - private Boolean includeAnnotationConfig = null; - private String resourcePattern = null; - private List basePackages = new ArrayList(); - private Object beanNameGenerator = null; - private Object scopeMetadataResolver = null; - private Object scopedProxyMode = null; - private Boolean useDefaultFilters = null; - private List includeFilters = new ArrayList(); - private List excludeFilters = new ArrayList(); - - 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 nullSafeTypedObject(Object object, Class 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 packages = new ArrayList(); - 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) 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)); - } - - } - } - - -} diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java index 88dc2778f6c..06e16297ade 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java @@ -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 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)); } diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassEnhancer.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassEnhancer.java index 9e0e546b585..2e4bc37de9b 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassEnhancer.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassEnhancer.java @@ -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); diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java index 1c821f5ff66..01cbd8ee40a 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java @@ -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 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 retrieveFeatureConfigurationBeans(ConfigurableListableBeanFactory beanFactory) { - Map fcBeans = new HashMap(); - 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 beanArgs = new ArrayList(); - 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 configCandidates = new LinkedHashSet(); 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 { diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationMethod.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationMethod.java new file mode 100644 index 00000000000..624be36d0dc --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationMethod.java @@ -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()); + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/EarlyBeanReferenceProxy.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/EarlyBeanReferenceProxy.java deleted file mode 100644 index c0cd0965496..00000000000 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/EarlyBeanReferenceProxy.java +++ /dev/null @@ -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(); - -} diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/EarlyBeanReferenceProxyCreator.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/EarlyBeanReferenceProxyCreator.java deleted file mode 100644 index e7480a2de30..00000000000 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/EarlyBeanReferenceProxyCreator.java +++ /dev/null @@ -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); - } - - } - -} - diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/Feature.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/Feature.java deleted file mode 100644 index dc54a0e94d7..00000000000 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/Feature.java +++ /dev/null @@ -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 { - -} \ No newline at end of file diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/FeatureAnnotation.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/FeatureAnnotation.java deleted file mode 100644 index 20bb2802ba0..00000000000 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/FeatureAnnotation.java +++ /dev/null @@ -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}. - * - *

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 parser(); - -} diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/FeatureAnnotationParser.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/FeatureAnnotationParser.java deleted file mode 100644 index 65a402de417..00000000000 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/FeatureAnnotationParser.java +++ /dev/null @@ -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. - * - *

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 } 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. - * - *

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); - -} diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/FeatureConfiguration.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/FeatureConfiguration.java deleted file mode 100644 index 6fbfbf2b98b..00000000000 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/FeatureConfiguration.java +++ /dev/null @@ -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. - * - *

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 ""; -} diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/FeatureMethodExecutionException.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/FeatureMethodExecutionException.java deleted file mode 100644 index e5aa6f54365..00000000000 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/FeatureMethodExecutionException.java +++ /dev/null @@ -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); - } -} diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/ProxyCreationException.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/ProxyCreationException.java deleted file mode 100644 index f85f311f83e..00000000000 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/ProxyCreationException.java +++ /dev/null @@ -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); - } - -} diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/SimpleComponentRegistrar.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/SimpleComponentRegistrar.java deleted file mode 100644 index d812f2983c0..00000000000 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/SimpleComponentRegistrar.java +++ /dev/null @@ -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 - } -} diff --git a/org.springframework.context/src/main/java/org/springframework/context/config/AbstractFeatureSpecification.java b/org.springframework.context/src/main/java/org/springframework/context/config/AbstractFeatureSpecification.java deleted file mode 100644 index 0fde6301a2e..00000000000 --- a/org.springframework.context/src/main/java/org/springframework/context/config/AbstractFeatureSpecification.java +++ /dev/null @@ -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 executorType; - - private Object source = DUMMY_SOURCE; - private String sourceName = DUMMY_SOURCE_NAME; - - protected AbstractFeatureSpecification(Class 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); - } - -} diff --git a/org.springframework.context/src/main/java/org/springframework/context/config/AbstractSpecificationBeanDefinitionParser.java b/org.springframework.context/src/main/java/org/springframework/context/config/AbstractSpecificationBeanDefinitionParser.java deleted file mode 100644 index 58472b55142..00000000000 --- a/org.springframework.context/src/main/java/org/springframework/context/config/AbstractSpecificationBeanDefinitionParser.java +++ /dev/null @@ -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; - } - -} diff --git a/org.springframework.context/src/main/java/org/springframework/context/config/AbstractSpecificationExecutor.java b/org.springframework.context/src/main/java/org/springframework/context/config/AbstractSpecificationExecutor.java deleted file mode 100644 index 2f53047076e..00000000000 --- a/org.springframework.context/src/main/java/org/springframework/context/config/AbstractSpecificationExecutor.java +++ /dev/null @@ -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 implements FeatureSpecificationExecutor { - - /** - * {@inheritDoc} - *

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); - -} diff --git a/org.springframework.context/src/main/java/org/springframework/context/config/FeatureSpecification.java b/org.springframework.context/src/main/java/org/springframework/context/config/FeatureSpecification.java deleted file mode 100644 index 671414f9a58..00000000000 --- a/org.springframework.context/src/main/java/org/springframework/context/config/FeatureSpecification.java +++ /dev/null @@ -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. - * - *

Many features of the Spring container can be configured using either XML or annotations. - * As one example, Spring's component scanning feature may be configured using - * either the {@code } 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 specifying 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. - * - *

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. - * - *

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. - * - *

{@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. - * - *

Notes on designing {@code FeatureSpecification} implementations

- * - *

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: - * - *

- * @Feature
- * public TxAnnotationDriven tx(PlatformTransactionManager txManager) {
- *    return new TxAnnotationDriven(txManager).proxyTargetClass(true);
- * }
- * 
- * - * 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: - * - *

{@code } - * - *

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. - * - *

Implementations should take care to allow for use of string-based bean names, placeholder - * ("${...}") and SpEL ("#{...}) 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. - * - *

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); - -} diff --git a/org.springframework.context/src/main/java/org/springframework/context/config/FeatureSpecificationExecutor.java b/org.springframework.context/src/main/java/org/springframework/context/config/FeatureSpecificationExecutor.java deleted file mode 100644 index 47237e33039..00000000000 --- a/org.springframework.context/src/main/java/org/springframework/context/config/FeatureSpecificationExecutor.java +++ /dev/null @@ -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); - -} diff --git a/org.springframework.context/src/main/java/org/springframework/context/config/SourceAwareSpecification.java b/org.springframework.context/src/main/java/org/springframework/context/config/SourceAwareSpecification.java deleted file mode 100644 index 82b6ea09cdd..00000000000 --- a/org.springframework.context/src/main/java/org/springframework/context/config/SourceAwareSpecification.java +++ /dev/null @@ -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); - -} diff --git a/org.springframework.context/src/main/java/org/springframework/context/config/SpecificationContext.java b/org.springframework.context/src/main/java/org/springframework/context/config/SpecificationContext.java deleted file mode 100644 index 20c2d2ea363..00000000000 --- a/org.springframework.context/src/main/java/org/springframework/context/config/SpecificationContext.java +++ /dev/null @@ -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; - } - -} diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/BeanFactoryAwareFeatureConfigurationTests.java b/org.springframework.context/src/test/java/org/springframework/context/annotation/BeanFactoryAwareFeatureConfigurationTests.java deleted file mode 100644 index 42f1c9b2a27..00000000000 --- a/org.springframework.context/src/test/java/org/springframework/context/annotation/BeanFactoryAwareFeatureConfigurationTests.java +++ /dev/null @@ -1,67 +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 static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; - -import org.junit.Test; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.BeanFactoryAware; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.context.annotation.configuration.StubSpecification; -import org.springframework.context.config.FeatureSpecification; - -/** - * Tests that @FeatureConfiguration classes may implement Aware interfaces, - * such as BeanFactoryAware. This is not generally recommended but occasionally - * useful, particularly in testing. - * - * @author Chris Beams - * @since 3.1 - */ -public class BeanFactoryAwareFeatureConfigurationTests { - @Test - public void test() { - ConfigurableApplicationContext ctx = - new AnnotationConfigApplicationContext(FeatureConfig.class); - FeatureConfig fc = ctx.getBean(FeatureConfig.class); - assertThat(fc.featureMethodWasCalled, is(true)); - assertThat(fc.gotBeanFactoryInTime, is(true)); - assertThat(fc.beanFactory, is(ctx.getBeanFactory())); - } - - @FeatureConfiguration - static class FeatureConfig implements BeanFactoryAware { - - ConfigurableListableBeanFactory beanFactory; - boolean featureMethodWasCalled = false; - boolean gotBeanFactoryInTime = false; - - public void setBeanFactory(BeanFactory beanFactory) { - this.beanFactory = (ConfigurableListableBeanFactory)beanFactory; - } - - @Feature - public FeatureSpecification f() { - this.featureMethodWasCalled = true; - this.gotBeanFactoryInTime = (this.beanFactory != null); - return new StubSpecification(); - } - } -} diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/ComponentScanExecutorTests.java b/org.springframework.context/src/test/java/org/springframework/context/annotation/ComponentScanExecutorTests.java deleted file mode 100644 index f419f1e8ee3..00000000000 --- a/org.springframework.context/src/test/java/org/springframework/context/annotation/ComponentScanExecutorTests.java +++ /dev/null @@ -1,67 +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 static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; - -import org.junit.Before; -import org.junit.Test; -import org.springframework.beans.factory.parsing.BeanDefinitionParsingException; -import org.springframework.beans.factory.parsing.FailFastProblemReporter; -import org.springframework.beans.factory.support.DefaultListableBeanFactory; -import org.springframework.context.config.SpecificationContext; -import org.springframework.core.io.DefaultResourceLoader; -import org.springframework.mock.env.MockEnvironment; - -/** - * Unit tests for {@link ComponentScanExecutor}. - * - * @author Chris Beams - * @since 3.1 - */ -public class ComponentScanExecutorTests { - - private ComponentScanExecutor executor; - private SpecificationContext specificationContext; - private DefaultListableBeanFactory bf; - - @Before - public void setUp() { - this.bf = new DefaultListableBeanFactory(); - this.executor = new ComponentScanExecutor(); - this.specificationContext = new SpecificationContext(); - this.specificationContext.setRegistry(bf); - this.specificationContext.setResourceLoader(new DefaultResourceLoader()); - this.specificationContext.setEnvironment(new MockEnvironment()); - this.specificationContext.setRegistrar(new SimpleComponentRegistrar(bf)); - this.specificationContext.setProblemReporter(new FailFastProblemReporter()); - } - - @Test - public void validSpec() { - this.executor.execute(new ComponentScanSpec("example.scannable"), this.specificationContext); - assertThat(bf.containsBean("fooServiceImpl"), is(true)); - } - - @Test(expected=BeanDefinitionParsingException.class) - public void invalidSpec() { - // ff problem reporter should throw due to no packages specified - this.executor.execute(new ComponentScanSpec(), this.specificationContext); - } - -} diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/ComponentScanFeatureTests.java b/org.springframework.context/src/test/java/org/springframework/context/annotation/ComponentScanFeatureTests.java deleted file mode 100644 index 8ddbd03240f..00000000000 --- a/org.springframework.context/src/test/java/org/springframework/context/annotation/ComponentScanFeatureTests.java +++ /dev/null @@ -1,55 +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 static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; - -import org.junit.Test; - -public class ComponentScanFeatureTests { - @Test - public void viaContextRegistration() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); - ctx.register(ComponentScanFeatureConfig.class); - ctx.register(ComponentScanFeatureConfig.Features.class); - ctx.refresh(); - ctx.getBean(ComponentScanFeatureConfig.class); - ctx.getBean(TestBean.class); - assertThat("config class bean not found", ctx.containsBeanDefinition("componentScanFeatureConfig"), is(true)); - assertThat("@ComponentScan annotated @Configuration class registered directly against " + - "AnnotationConfigApplicationContext did not trigger component scanning as expected", - ctx.containsBean("fooServiceImpl"), is(true)); - } -} - -@Configuration -//@Import(ComponentScanFeatureConfig.Features.class) -class ComponentScanFeatureConfig { - @FeatureConfiguration - static class Features { - @Feature - public ComponentScanSpec componentScan() { - return new ComponentScanSpec(example.scannable._package.class); - } - } - - @Bean - public TestBean testBean() { - return new TestBean(); - } -} \ No newline at end of file diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/ComponentScanSpecTests.java b/org.springframework.context/src/test/java/org/springframework/context/annotation/ComponentScanSpecTests.java deleted file mode 100644 index cc9f1ecbb81..00000000000 --- a/org.springframework.context/src/test/java/org/springframework/context/annotation/ComponentScanSpecTests.java +++ /dev/null @@ -1,411 +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 static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.instanceOf; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.nullValue; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.springframework.util.StringUtils.arrayToCommaDelimitedString; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import org.junit.Before; -import org.junit.Test; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.parsing.BeanDefinitionParsingException; -import org.springframework.beans.factory.parsing.FailFastProblemReporter; -import org.springframework.beans.factory.parsing.Problem; -import org.springframework.beans.factory.parsing.ProblemReporter; -import org.springframework.beans.factory.support.BeanNameGenerator; -import org.springframework.beans.factory.support.DefaultBeanNameGenerator; -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.AssignableTypeFilter; -import org.springframework.core.type.filter.TypeFilter; -import org.springframework.util.ClassUtils; -import org.springframework.util.ObjectUtils; - -/** - * Unit tests for {@link ComponentScanSpec}. - * - * @author Chris Beams - * @since 3.1 - */ -public class ComponentScanSpecTests { - - private CollatingProblemReporter problemReporter; - private ClassLoader classLoader; - - - @Before - public void setUp() { - problemReporter = new CollatingProblemReporter(); - classLoader = ClassUtils.getDefaultClassLoader(); - } - - @Test - public void includeAnnotationConfig() { - ComponentScanSpec spec = new ComponentScanSpec("org.p1"); - assertThat(spec.includeAnnotationConfig(), nullValue()); - spec.includeAnnotationConfig(true); - assertThat(spec.validate(problemReporter), is(true)); - assertThat(spec.includeAnnotationConfig(), is(true)); - spec.includeAnnotationConfig(false); - assertThat(spec.validate(problemReporter), is(true)); - assertThat(spec.includeAnnotationConfig(), is(false)); - spec.includeAnnotationConfig("trUE"); - assertThat(spec.validate(problemReporter), is(true)); - assertThat(spec.includeAnnotationConfig(), is(true)); - spec.includeAnnotationConfig("falSE"); - assertThat(spec.validate(problemReporter), is(true)); - assertThat(spec.includeAnnotationConfig(), is(false)); - spec.includeAnnotationConfig(""); - assertThat(spec.validate(problemReporter), is(true)); - assertThat(spec.includeAnnotationConfig(), is(false)); - spec.includeAnnotationConfig((String)null); - assertThat(spec.validate(problemReporter), is(true)); - assertThat(spec.includeAnnotationConfig(), is(false)); - spec.includeAnnotationConfig((Boolean)null); - assertThat(spec.validate(problemReporter), is(true)); - assertThat(spec.includeAnnotationConfig(), nullValue()); - } - - @Test - public void resourcePattern() { - ComponentScanSpec spec = new ComponentScanSpec("org.p1"); - assertThat(spec.resourcePattern(), nullValue()); - assertThat(spec.validate(problemReporter), is(true)); - spec.resourcePattern("**/Foo*.class"); - assertThat(spec.resourcePattern(), is("**/Foo*.class")); - assertThat(spec.validate(problemReporter), is(true)); - spec.resourcePattern(""); - assertThat(spec.resourcePattern(), is("**/Foo*.class")); - assertThat(spec.validate(problemReporter), is(true)); - spec.resourcePattern(null); - assertThat(spec.resourcePattern(), is("**/Foo*.class")); - assertThat(spec.validate(problemReporter), is(true)); - } - - @Test - public void useDefaultFilters() { - ComponentScanSpec spec = new ComponentScanSpec("org.p1"); - assertThat(spec.useDefaultFilters(), nullValue()); - assertThat(spec.validate(problemReporter), is(true)); - spec.useDefaultFilters((Boolean)null); - assertThat(spec.useDefaultFilters(), nullValue()); - assertThat(spec.validate(problemReporter), is(true)); - spec.useDefaultFilters(true); - assertThat(spec.useDefaultFilters(), is(true)); - assertThat(spec.validate(problemReporter), is(true)); - spec.useDefaultFilters(false); - assertThat(spec.useDefaultFilters(), is(false)); - assertThat(spec.validate(problemReporter), is(true)); - spec.useDefaultFilters("trUE"); - assertThat(spec.useDefaultFilters(), is(true)); - assertThat(spec.validate(problemReporter), is(true)); - spec.useDefaultFilters("falSE"); - assertThat(spec.useDefaultFilters(), is(false)); - assertThat(spec.validate(problemReporter), is(true)); - spec.useDefaultFilters(""); - assertThat(spec.useDefaultFilters(), is(false)); - assertThat(spec.validate(problemReporter), is(true)); - spec.useDefaultFilters((String)null); - assertThat(spec.useDefaultFilters(), is(false)); - assertThat(spec.validate(problemReporter), is(true)); - } - - @Test - public void includeFilters() { - ComponentScanSpec spec = new ComponentScanSpec("org.p1"); - spec.includeFilters( - new AnnotationTypeFilter(MyAnnotation.class), - new AssignableTypeFilter(Object.class)); - assertThat(spec.validate(problemReporter), is(true)); - assertThat(spec.includeFilters().length, is(2)); - } - - @Test - public void stringIncludeExcludeFilters() { - ComponentScanSpec spec = new ComponentScanSpec("org.p1"); - spec.addIncludeFilter("annotation", MyAnnotation.class.getName(), classLoader); - spec.addExcludeFilter("assignable", Object.class.getName(), classLoader); - spec.addExcludeFilter("annotation", Override.class.getName(), classLoader); - assertThat(spec.validate(problemReporter), is(true)); - assertThat(spec.includeFilters().length, is(1)); - assertThat(spec.excludeFilters().length, is(2)); - } - - @Test - public void bogusStringIncludeFilter() throws IOException { - ComponentScanSpec spec = new ComponentScanSpec("org.p1"); - spec.addIncludeFilter("bogus-type", "bogus-expr", classLoader); - assertThat(spec.validate(problemReporter), is(false)); - assertThat(spec.includeFilters().length, is(1)); - try { - spec.includeFilters()[0].match(null, null); - fail("expected placholder TypeFilter to throw exception"); - } catch (UnsupportedOperationException ex) { - // expected - } - } - - @Test - public void exerciseFilterTypes() throws IOException { - ComponentScanSpec spec = new ComponentScanSpec("org.p1"); - spec.addIncludeFilter("aspectj", "*..Bogus", classLoader); - assertThat(spec.validate(problemReporter), is(true)); - spec.addIncludeFilter("regex", ".*Foo", classLoader); - assertThat(spec.validate(problemReporter), is(true)); - spec.addIncludeFilter("custom", StubTypeFilter.class.getName(), classLoader); - assertThat(spec.validate(problemReporter), is(true)); - spec.addIncludeFilter("custom", "org.NonExistentTypeFilter", classLoader); - assertThat(spec.validate(problemReporter), is(false)); - spec.addIncludeFilter("custom", NonNoArgResolver.class.getName(), classLoader); - assertThat(spec.validate(problemReporter), is(false)); - } - - @Test - public void missingBasePackages() { - ComponentScanSpec spec = new ComponentScanSpec(); - assertThat(spec.validate(problemReporter), is(false)); - } - - @Test - public void withBasePackageViaAdderMethod() { - ComponentScanSpec spec = new ComponentScanSpec(); - spec.addBasePackage("org.p1"); - spec.addBasePackage("org.p2"); - assertThat(spec.validate(problemReporter), is(true)); - assertExactContents(spec.basePackages(), "org.p1", "org.p2"); - } - - @Test - public void withBasePackagesViaStringConstructor() { - ComponentScanSpec spec = new ComponentScanSpec("org.p1", "org.p2"); - assertThat(spec.validate(problemReporter), is(true)); - assertExactContents(spec.basePackages(), "org.p1", "org.p2"); - } - - @Test - public void withBasePackagesViaClassConstructor() { - ComponentScanSpec spec = new ComponentScanSpec(java.lang.Object.class, java.io.Closeable.class); - assertThat(spec.validate(problemReporter), is(true)); - assertExactContents(spec.basePackages(), "java.lang", "java.io"); - } - - @Test - public void forDelimitedPackages() { - ComponentScanSpec spec = ComponentScanSpec.forDelimitedPackages("pkg.one,pkg.two"); - assertTrue(ObjectUtils.containsElement(spec.basePackages(), "pkg.one")); - assertTrue(ObjectUtils.containsElement(spec.basePackages(), "pkg.two")); - assertThat(spec.basePackages().length, is(2)); - } - - @Test - public void withSomeEmptyBasePackages() { - ComponentScanSpec spec = new ComponentScanSpec("org.p1", "", "org.p3"); - assertThat(spec.validate(problemReporter), is(true)); - assertExactContents(spec.basePackages(), "org.p1", "org.p3"); - } - - @Test - public void withAllEmptyBasePackages() { - ComponentScanSpec spec = new ComponentScanSpec("", "", ""); - assertThat(spec.validate(problemReporter), is(false)); - } - - @Test - public void withInstanceBeanNameGenerator() { - ComponentScanSpec spec = new ComponentScanSpec("org.p1"); - assertThat(spec.beanNameGenerator(), nullValue()); - BeanNameGenerator bng = new DefaultBeanNameGenerator(); - spec.beanNameGenerator(bng); - assertThat(spec.validate(problemReporter), is(true)); - assertThat(spec.beanNameGenerator(), is(bng)); - } - - @Test - public void withStringBeanNameGenerator() { - ComponentScanSpec spec = new ComponentScanSpec("org.p1"); - spec.beanNameGenerator(DefaultBeanNameGenerator.class.getName(), classLoader); - assertThat(spec.validate(problemReporter), is(true)); - assertThat(spec.beanNameGenerator(), instanceOf(DefaultBeanNameGenerator.class)); - } - - @Test - public void withInstanceScopeMetadataResolver() { - ComponentScanSpec spec = new ComponentScanSpec("org.p1"); - assertThat(spec.scopeMetadataResolver(), nullValue()); - ScopeMetadataResolver smr = new AnnotationScopeMetadataResolver(); - spec.scopeMetadataResolver(smr); - assertThat(spec.validate(problemReporter), is(true)); - assertThat(spec.scopeMetadataResolver(), is(smr)); - } - - @Test - public void withStringScopeMetadataResolver() { - ComponentScanSpec spec = new ComponentScanSpec("org.p1"); - spec.scopeMetadataResolver(AnnotationScopeMetadataResolver.class.getName(), classLoader); - assertThat(spec.validate(problemReporter), is(true)); - assertThat(spec.scopeMetadataResolver(), instanceOf(AnnotationScopeMetadataResolver.class)); - } - - @Test - public void withNonAssignableStringScopeMetadataResolver() { - ComponentScanSpec spec = new ComponentScanSpec("org.p1"); - spec.scopeMetadataResolver(Object.class.getName(), classLoader); - assertThat(spec.validate(problemReporter), is(false)); - } - - @Test - public void withNonExistentStringScopeMetadataResolver() { - ComponentScanSpec spec = new ComponentScanSpec("org.p1"); - spec.scopeMetadataResolver("org.Bogus", classLoader); - assertThat(spec.validate(problemReporter), is(false)); - } - - @Test - public void withNonNoArgStringScopeMetadataResolver() { - ComponentScanSpec spec = new ComponentScanSpec("org.p1"); - spec.scopeMetadataResolver(NonNoArgResolver.class.getName(), classLoader); - assertThat(spec.validate(problemReporter), is(false)); - } - - @Test - public void withStringScopedProxyMode() { - ComponentScanSpec spec = new ComponentScanSpec("org.p1"); - spec.scopedProxyMode("targetCLASS"); - assertThat(spec.validate(problemReporter), is(true)); - assertThat(spec.scopedProxyMode(), is(ScopedProxyMode.TARGET_CLASS)); - spec.scopedProxyMode("interFACES"); - assertThat(spec.validate(problemReporter), is(true)); - assertThat(spec.scopedProxyMode(), is(ScopedProxyMode.INTERFACES)); - spec.scopedProxyMode("nO"); - assertThat(spec.validate(problemReporter), is(true)); - assertThat(spec.scopedProxyMode(), is(ScopedProxyMode.NO)); - spec.scopedProxyMode("bogus"); - assertThat(spec.validate(problemReporter), is(false)); - assertThat(spec.scopedProxyMode(), nullValue()); - } - - @Test - public void withScopeMetadataResolverAndScopedProxyMode() { - ComponentScanSpec spec = new ComponentScanSpec("org.p1"); - spec.scopeMetadataResolver(new AnnotationScopeMetadataResolver()); - assertThat(spec.validate(problemReporter), is(true)); - spec.scopedProxyMode(ScopedProxyMode.INTERFACES); - assertThat(spec.validate(problemReporter), is(false)); - } - - @Test - public void addBasePackage() { - ComponentScanSpec spec = new ComponentScanSpec(); - spec.addBasePackage("foo.bar"); - assertThat(spec.validate(problemReporter), is(true)); - assertThat(spec.basePackages().length, is(1)); - } - - @Test - public void addBasePackageWithConstructor() { - ComponentScanSpec spec = new ComponentScanSpec("my.pkg"); - spec.addBasePackage("foo.bar"); - assertThat(spec.validate(problemReporter), is(true)); - assertThat(spec.basePackages().length, is(2)); - } - - @Test - public void addExcludeFilterString() { - ComponentScanSpec spec = new ComponentScanSpec("my.pkg"); - spec.addExcludeFilter("annotation", MyAnnotation.class.getName(), ClassUtils.getDefaultClassLoader()); - assertThat(spec.validate(problemReporter), is(true)); - assertThat(spec.excludeFilters().length, is(1)); - assertThat(spec.excludeFilters()[0], instanceOf(AnnotationTypeFilter.class)); - } - - @Test(expected=BeanDefinitionParsingException.class) - public void withFailFastProblemReporter() { - new ComponentScanSpec().validate(new FailFastProblemReporter()); - } - - private void assertExactContents(T[] actual, T... expected) { - if (actual.length >= expected.length) { - for (int i = 0; i < expected.length; i++) { - assertThat( - String.format("element number %d in actual is incorrect. actual: [%s], expected: [%s]", - i, arrayToCommaDelimitedString(actual), arrayToCommaDelimitedString(expected)), - actual[i], equalTo(expected[i])); - } - } - assertThat(String.format("actual contains incorrect number of arguments. actual: [%s], expected: [%s]", - arrayToCommaDelimitedString(actual), arrayToCommaDelimitedString(expected)), - actual.length, equalTo(expected.length)); - } - - - private static class CollatingProblemReporter implements ProblemReporter { - - private List errors = new ArrayList(); - - private List warnings = new ArrayList(); - - - public void fatal(Problem problem) { - throw new BeanDefinitionParsingException(problem); - } - - public void error(Problem problem) { - this.errors.add(problem); - } - - @SuppressWarnings("unused") - public Problem[] getErrors() { - return this.errors.toArray(new Problem[this.errors.size()]); - } - - public void warning(Problem problem) { - System.out.println(problem); - this.warnings.add(problem); - } - - @SuppressWarnings("unused") - public Problem[] getWarnings() { - return this.warnings.toArray(new Problem[this.warnings.size()]); - } - } - - - private static class NonNoArgResolver implements ScopeMetadataResolver { - public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) { - throw new UnsupportedOperationException(); - } - } - - private static class StubTypeFilter implements TypeFilter { - public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) - throws IOException { - throw new UnsupportedOperationException(); - } - } - -} \ No newline at end of file diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/EarlyBeanReferenceProxyCreatorTests.java b/org.springframework.context/src/test/java/org/springframework/context/annotation/EarlyBeanReferenceProxyCreatorTests.java deleted file mode 100644 index d5813821e7f..00000000000 --- a/org.springframework.context/src/test/java/org/springframework/context/annotation/EarlyBeanReferenceProxyCreatorTests.java +++ /dev/null @@ -1,312 +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 static java.lang.String.format; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.instanceOf; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.not; -import static org.hamcrest.CoreMatchers.sameInstance; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; -import static org.springframework.context.annotation.EarlyBeanReferenceProxyCreator.MISSING_NO_ARG_CONSTRUCTOR_ERROR_MESSAGE; -import static org.springframework.context.annotation.EarlyBeanReferenceProxyCreator.PRIVATE_NO_ARG_CONSTRUCTOR_ERROR_MESSAGE; - -import java.lang.reflect.Method; - -import org.junit.Before; -import org.junit.Test; -import org.springframework.aop.support.AopUtils; -import org.springframework.beans.factory.NoSuchBeanDefinitionException; -import org.springframework.beans.factory.config.DependencyDescriptor; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.support.DefaultListableBeanFactory; -import org.springframework.beans.factory.support.RootBeanDefinition; -import org.springframework.core.MethodParameter; - -import test.beans.ITestBean; -import test.beans.TestBean; - -/** - * Unit tests for {@link EarlyBeanReferenceProxyCreator}, ensuring that - * {@link EarlyBeanReferenceProxy} objects behave properly. - * - * @author Chris Beams - * @since 3.1 - */ -public class EarlyBeanReferenceProxyCreatorTests { - - private DefaultListableBeanFactory bf; - - @Before - public void setUp() { - bf = new DefaultListableBeanFactory(); - } - - @Test - public void proxyToStringAvoidsEagerInstantiation() throws Exception { - EarlyBeanReferenceProxyCreator pc = new EarlyBeanReferenceProxyCreator(bf); - - TestBean proxy = (TestBean) pc.createProxyIfPossible(descriptorFor(TestBean.class)); - - assertThat(proxy.toString(), equalTo("EarlyBeanReferenceProxy for bean of type TestBean")); - } - - @Test(expected=NoSuchBeanDefinitionException.class) - public void proxyThrowsNoSuchBeanDefinitionExceptionWhenDelegatingMethodCallToNonExistentBean() throws Exception { - EarlyBeanReferenceProxyCreator pc = new EarlyBeanReferenceProxyCreator(bf); - TestBean proxy = (TestBean) pc.createProxyIfPossible(descriptorFor(TestBean.class)); - - proxy.getName(); - } - - @Test - public void proxyHashCodeAvoidsEagerInstantiation() throws Exception { - EarlyBeanReferenceProxyCreator pc = new EarlyBeanReferenceProxyCreator(bf); - TestBean proxy = (TestBean) pc.createProxyIfPossible(descriptorFor(TestBean.class)); - - assertThat(proxy.hashCode(), equalTo(System.identityHashCode(proxy))); - } - - @Test - public void proxyEqualsAvoidsEagerInstantiation() throws Exception { - EarlyBeanReferenceProxyCreator pc = new EarlyBeanReferenceProxyCreator(bf); - - TestBean proxy = (TestBean) pc.createProxyIfPossible(descriptorFor(TestBean.class)); - - assertThat(proxy.equals(new Object()), is(false)); - assertThat(proxy.equals(proxy), is(true)); - - TestBean proxy2 = (TestBean) pc.createProxyIfPossible(descriptorFor(TestBean.class)); - - assertThat(proxy, not(sameInstance(proxy2))); - assertThat(proxy.equals(proxy2), is(false)); - assertThat(proxy2.equals(proxy), is(false)); - assertThat(proxy2.equals(proxy2), is(true)); - } - - @Test - public void proxyFinalizeAvoidsEagerInstantiation() throws Exception { - EarlyBeanReferenceProxyCreator pc = new EarlyBeanReferenceProxyCreator(bf); - - BeanWithFinalizer proxy = (BeanWithFinalizer) pc.createProxyIfPossible(descriptorFor(BeanWithFinalizer.class)); - - assertThat(BeanWithFinalizer.finalizerWasCalled, is(false)); - BeanWithFinalizer.class.getDeclaredMethod("finalize").invoke(proxy); - assertThat(BeanWithFinalizer.finalizerWasCalled, is(false)); - } - - @Test - public void proxyMethodsDelegateToTargetBeanCausingSingletonRegistrationIfNecessary() throws Exception { - bf.registerBeanDefinition("testBean", - BeanDefinitionBuilder.rootBeanDefinition(TestBean.class) - .addPropertyValue("name", "testBeanName").getBeanDefinition()); - EarlyBeanReferenceProxyCreator pc = new EarlyBeanReferenceProxyCreator(bf); - TestBean proxy = (TestBean) pc.createProxyIfPossible(descriptorFor(TestBean.class)); - - assertThat(bf.containsBeanDefinition("testBean"), is(true)); - assertThat(bf.containsSingleton("testBean"), is(false)); - assertThat(proxy.getName(), equalTo("testBeanName")); - assertThat(bf.containsSingleton("testBean"), is(true)); - } - - @Test - public void beanAnnotatedMethodsReturnEarlyProxyAsWell() throws Exception { - bf.registerBeanDefinition("componentWithInterfaceBeanMethod", new RootBeanDefinition(ComponentWithInterfaceBeanMethod.class)); - EarlyBeanReferenceProxyCreator pc = new EarlyBeanReferenceProxyCreator(bf); - ComponentWithInterfaceBeanMethod proxy = (ComponentWithInterfaceBeanMethod) pc.createProxyIfPossible(descriptorFor(ComponentWithInterfaceBeanMethod.class)); - - ITestBean bean = proxy.aBeanMethod(); - assertThat(bean, instanceOf(EarlyBeanReferenceProxy.class)); - assertThat(bf.containsBeanDefinition("componentWithInterfaceBeanMethod"), is(true)); - assertThat("calling a @Bean method on an EarlyBeanReferenceProxy object " + - "should not cause its instantation/registration", - bf.containsSingleton("componentWithInterfaceBeanMethod"), is(false)); - - Object obj = proxy.normalInstanceMethod(); - assertThat(bf.containsSingleton("componentWithInterfaceBeanMethod"), is(true)); - assertThat(obj, not(instanceOf(EarlyBeanReferenceProxy.class))); - } - - @Test - public void proxiesReturnedFromBeanAnnotatedMethodsDereferenceAndDelegateToTheirTargetBean() throws Exception { - bf.registerBeanDefinition("componentWithConcreteBeanMethod", new RootBeanDefinition(ComponentWithConcreteBeanMethod.class)); - RootBeanDefinition beanMethodBeanDef = new RootBeanDefinition(); - beanMethodBeanDef.setFactoryBeanName("componentWithConcreteBeanMethod"); - beanMethodBeanDef.setFactoryMethodName("aBeanMethod"); - bf.registerBeanDefinition("aBeanMethod", beanMethodBeanDef); - EarlyBeanReferenceProxyCreator pc = new EarlyBeanReferenceProxyCreator(bf); - ComponentWithConcreteBeanMethod proxy = (ComponentWithConcreteBeanMethod) pc.createProxyIfPossible(descriptorFor(ComponentWithConcreteBeanMethod.class)); - - TestBean bean = proxy.aBeanMethod(); - assertThat(bean.getName(), equalTo("concrete")); - } - - @Test - public void interfaceBeansAreProxied() throws Exception { - EarlyBeanReferenceProxyCreator pc = new EarlyBeanReferenceProxyCreator(bf); - ITestBean proxy = (ITestBean) pc.createProxyIfPossible(descriptorFor(ITestBean.class)); - - assertThat(proxy, instanceOf(EarlyBeanReferenceProxy.class)); - assertThat(AopUtils.isCglibProxyClass(proxy.getClass()), is(true)); - assertEquals( - "interface-based bean proxies should have Object as superclass", - proxy.getClass().getSuperclass(), Object.class); - } - - @Test - public void concreteBeansAreProxied() throws Exception { - EarlyBeanReferenceProxyCreator pc = new EarlyBeanReferenceProxyCreator(bf); - TestBean proxy = (TestBean) pc.createProxyIfPossible(descriptorFor(TestBean.class)); - - assertThat(proxy, instanceOf(EarlyBeanReferenceProxy.class)); - assertThat(AopUtils.isCglibProxyClass(proxy.getClass()), is(true)); - assertEquals( - "concrete bean proxies should have the bean class as superclass", - proxy.getClass().getSuperclass(), TestBean.class); - } - - @Test - public void beanAnnotatedMethodsWithInterfaceReturnTypeAreProxied() throws Exception { - bf.registerBeanDefinition("componentWithInterfaceBeanMethod", new RootBeanDefinition(ComponentWithInterfaceBeanMethod.class)); - EarlyBeanReferenceProxyCreator pc = new EarlyBeanReferenceProxyCreator(bf); - ComponentWithInterfaceBeanMethod proxy = (ComponentWithInterfaceBeanMethod) pc.createProxyIfPossible(descriptorFor(ComponentWithInterfaceBeanMethod.class)); - - ITestBean bean = proxy.aBeanMethod(); - assertThat(bean, instanceOf(EarlyBeanReferenceProxy.class)); - assertThat(AopUtils.isCglibProxyClass(bean.getClass()), is(true)); - assertEquals( - "interface-based bean proxies should have Object as superclass", - bean.getClass().getSuperclass(), Object.class); - } - - @Test - public void beanAnnotatedMethodsWithConcreteReturnTypeAreProxied() throws Exception { - bf.registerBeanDefinition("componentWithConcreteBeanMethod", new RootBeanDefinition(ComponentWithConcreteBeanMethod.class)); - EarlyBeanReferenceProxyCreator pc = new EarlyBeanReferenceProxyCreator(bf); - ComponentWithConcreteBeanMethod proxy = (ComponentWithConcreteBeanMethod) pc.createProxyIfPossible(descriptorFor(ComponentWithConcreteBeanMethod.class)); - - TestBean bean = proxy.aBeanMethod(); - assertThat(bean, instanceOf(EarlyBeanReferenceProxy.class)); - assertThat(AopUtils.isCglibProxyClass(bean.getClass()), is(true)); - assertEquals( - "concrete bean proxies should have the bean class as superclass", - bean.getClass().getSuperclass(), TestBean.class); - } - - @Test - public void attemptToProxyClassMissingNoArgConstructorFailsGracefully() throws Exception { - EarlyBeanReferenceProxyCreator pc = new EarlyBeanReferenceProxyCreator(bf); - try { - pc.createProxyIfPossible(descriptorFor(BeanMissingNoArgConstructor.class)); - fail("expected ProxyCreationException"); - } catch(ProxyCreationException ex) { - assertThat(ex.getMessage(), - equalTo(format(MISSING_NO_ARG_CONSTRUCTOR_ERROR_MESSAGE, BeanMissingNoArgConstructor.class.getName()))); - } - } - - @Test - public void attemptToProxyClassWithPrivateNoArgConstructorFailsGracefully() throws Exception { - EarlyBeanReferenceProxyCreator pc = new EarlyBeanReferenceProxyCreator(bf); - try { - pc.createProxyIfPossible(descriptorFor(BeanWithPrivateNoArgConstructor.class)); - fail("expected ProxyCreationException"); - } catch(ProxyCreationException ex) { - assertThat(ex.getMessage(), - equalTo(format(PRIVATE_NO_ARG_CONSTRUCTOR_ERROR_MESSAGE, BeanWithPrivateNoArgConstructor.class.getName()))); - } - } - - @Test - public void attemptToProxyFinalClassReturnsNonProxiedInstance() throws Exception { - bf.registerBeanDefinition("finalBean", new RootBeanDefinition(FinalBean.class)); - EarlyBeanReferenceProxyCreator pc = new EarlyBeanReferenceProxyCreator(bf); - Object bean = pc.createProxyIfPossible(descriptorFor(FinalBean.class)); - assertThat(bean, instanceOf(FinalBean.class)); - assertThat(bean, not(instanceOf(EarlyBeanReferenceProxy.class))); - } - - private DependencyDescriptor descriptorFor(Class paramType) throws Exception { - @SuppressWarnings("unused") - class C { - void m(ITestBean p) { } - void m(TestBean p) { } - void m(BeanMissingNoArgConstructor p) { } - void m(BeanWithPrivateNoArgConstructor p) { } - void m(FinalBean p) { } - void m(BeanWithFinalizer p) { } - void m(ComponentWithConcreteBeanMethod p) { } - void m(ComponentWithInterfaceBeanMethod p) { } - } - - Method targetMethod = C.class.getDeclaredMethod("m", new Class[] { paramType }); - MethodParameter mp = new MethodParameter(targetMethod, 0); - DependencyDescriptor dd = new DependencyDescriptor(mp, true, false); - return dd; - } - - - static class BeanMissingNoArgConstructor { - BeanMissingNoArgConstructor(Object o) { } - } - - - static class BeanWithPrivateNoArgConstructor { - private BeanWithPrivateNoArgConstructor() { } - } - - - static final class FinalBean { - } - - - static class BeanWithFinalizer { - static Boolean finalizerWasCalled = false; - - @Override - protected void finalize() throws Throwable { - finalizerWasCalled = true; - } - } - - - static class ComponentWithConcreteBeanMethod { - @Bean - public TestBean aBeanMethod() { - return new TestBean("concrete"); - } - - public Object normalInstanceMethod() { - return new Object(); - } - } - - - static class ComponentWithInterfaceBeanMethod { - @Bean - public ITestBean aBeanMethod() { - return new TestBean("interface"); - } - - public Object normalInstanceMethod() { - return new Object(); - } - } -} diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/FeatureConfigurationClassTests.java b/org.springframework.context/src/test/java/org/springframework/context/annotation/FeatureConfigurationClassTests.java deleted file mode 100644 index e2610ac3b06..00000000000 --- a/org.springframework.context/src/test/java/org/springframework/context/annotation/FeatureConfigurationClassTests.java +++ /dev/null @@ -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.annotation; - -import static org.hamcrest.CoreMatchers.instanceOf; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; - -import org.junit.Test; -import org.springframework.context.annotation.configuration.StubSpecification; -import org.springframework.context.config.FeatureSpecification; -import org.springframework.core.env.Environment; -import org.springframework.core.io.ResourceLoader; -import org.springframework.mock.env.MockEnvironment; - -public class FeatureConfigurationClassTests { - - @Test(expected=FeatureMethodExecutionException.class) - public void featureConfigurationClassesMustNotContainBeanAnnotatedMethods() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); - ctx.register(FeatureConfigWithBeanAnnotatedMethod.class); - ctx.refresh(); - } - - @Test - public void featureMethodsMayAcceptResourceLoaderParameter() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); - ctx.setDisplayName("enclosing app ctx"); - ctx.setEnvironment(new MockEnvironment().withProperty("foo", "bar")); - ctx.register(FeatureMethodWithResourceLoaderParameter.class); - ctx.refresh(); - } - -} - - -@FeatureConfiguration -class FeatureConfigWithBeanAnnotatedMethod { - /** - * This is illegal use. @FeatureConfiguration classes cannot have @Bean methods. - */ - @Bean - public TestBean testBean() { - return new TestBean(); - } - - /** - * This will never get called. An exception will first be raised regarding the illegal @Bean method above. - */ - @Feature - public FeatureSpecification feature() { - return new StubSpecification(); - } -} - -@FeatureConfiguration -class FeatureMethodWithResourceLoaderParameter { - @Feature - public FeatureSpecification feature(ResourceLoader rl, - Environment e) { - // prove that the injected Environment is that of the enclosing app context - assertThat(e.getProperty("foo"), is("bar")); - // prove that the injected ResourceLoader is actually the enclosing application context - Object target = ((EarlyBeanReferenceProxy)rl).dereferenceTargetBean(); - assertThat(target, instanceOf(AnnotationConfigApplicationContext.class)); - assertThat(((AnnotationConfigApplicationContext)target).getDisplayName(), is("enclosing app ctx")); - return new StubSpecification(); - } -} \ No newline at end of file diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/FeatureConfigurationImportResourceTests-context.xml b/org.springframework.context/src/test/java/org/springframework/context/annotation/FeatureConfigurationImportResourceTests-context.xml deleted file mode 100644 index 930cadfa379..00000000000 --- a/org.springframework.context/src/test/java/org/springframework/context/annotation/FeatureConfigurationImportResourceTests-context.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/FeatureConfigurationImportResourceTests.java b/org.springframework.context/src/test/java/org/springframework/context/annotation/FeatureConfigurationImportResourceTests.java deleted file mode 100644 index 466e65b14e3..00000000000 --- a/org.springframework.context/src/test/java/org/springframework/context/annotation/FeatureConfigurationImportResourceTests.java +++ /dev/null @@ -1,69 +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 static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.instanceOf; -import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertThat; - -import org.junit.Test; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.configuration.StubSpecification; -import org.springframework.context.config.FeatureSpecification; - -import test.beans.TestBean; - -/** - * Tests proving that @FeatureConfiguration classes may be use @ImportResource - * and then parameter autowire beans declared in the imported resource(s). - * - * @author Chris Beams - * @since 3.1 - */ -public class FeatureConfigurationImportResourceTests { - - @Test - public void importResourceFromFeatureConfiguration() { - ApplicationContext ctx = - new AnnotationConfigApplicationContext(ImportingFeatureConfig.class); - TestBean testBean = ctx.getBean(TestBean.class); - assertThat(testBean.getName(), equalTo("beanFromXml")); - - // and just quickly prove that the target of the bean proxied for the Feature method - // is indeed the same singleton instance as the one we just pulled from the container - ImportingFeatureConfig ifc = ctx.getBean(ImportingFeatureConfig.class); - TestBean proxyBean = ifc.testBean; - assertThat(proxyBean, instanceOf(EarlyBeanReferenceProxy.class)); - assertNotSame(proxyBean, testBean); - assertSame(((EarlyBeanReferenceProxy)proxyBean).dereferenceTargetBean(), testBean); - } - - @FeatureConfiguration - @ImportResource("org/springframework/context/annotation/FeatureConfigurationImportResourceTests-context.xml") - static class ImportingFeatureConfig { - TestBean testBean; - - @Feature - public FeatureSpecification f(TestBean testBean) { - this.testBean = testBean; - return new StubSpecification(); - } - } - -} diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/FeatureConfigurationImportTests.java b/org.springframework.context/src/test/java/org/springframework/context/annotation/FeatureConfigurationImportTests.java deleted file mode 100644 index 53141541225..00000000000 --- a/org.springframework.context/src/test/java/org/springframework/context/annotation/FeatureConfigurationImportTests.java +++ /dev/null @@ -1,105 +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 static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; - -import org.junit.Test; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.context.annotation.configuration.StubSpecification; -import org.springframework.context.config.FeatureSpecification; - -/** - * Tests proving that @Configuration classes may @Import @FeatureConfiguration - * classes, and vice versa. - * - * @author Chris Beams - * @since 3.1 - */ -public class FeatureConfigurationImportTests { - - @Test - public void importFeatureConfigurationFromConfiguration() { - ConfigurableApplicationContext ctx = - new AnnotationConfigApplicationContext(ImportingConfig.class); - ImportedFeatureConfig ifc = ctx.getBean(ImportedFeatureConfig.class); - assertThat( - "@FeatureConfiguration class was imported and registered " + - "as a bean but its @Feature method was never called", - ifc.featureMethodWasCalled, is(true)); - } - - @Test - public void importConfigurationFromFeatureConfiguration() { - ConfigurableApplicationContext ctx = - new AnnotationConfigApplicationContext(ImportingFeatureConfig.class); - ImportingFeatureConfig ifc = ctx.getBean(ImportingFeatureConfig.class); - ImportedConfig ic = ctx.getBean(ImportedConfig.class); - assertThat( - "@FeatureConfiguration class was registered directly against " + - "the container but its @Feature method was never called", - ifc.featureMethodWasCalled, is(true)); - assertThat( - "@Configuration class was @Imported but its @Bean method" + - "was never registered / called", - ic.beanMethodWasCalled, is(true)); - } - - - @Configuration - @Import(ImportedFeatureConfig.class) - static class ImportingConfig { - } - - - @FeatureConfiguration - static class ImportedFeatureConfig { - boolean featureMethodWasCalled = false; - - @Feature - public FeatureSpecification f() { - this.featureMethodWasCalled = true; - return new StubSpecification(); - } - } - - - @Configuration - static class ImportedConfig { - boolean beanMethodWasCalled = true; - @Bean - public TestBean testBean() { - this.beanMethodWasCalled = true; - return new TestBean(); - } - } - - - @FeatureConfiguration - @Import(ImportedConfig.class) - static class ImportingFeatureConfig { - boolean featureMethodWasCalled = false; - - @Feature - public FeatureSpecification f() { - this.featureMethodWasCalled = true; - return new StubSpecification(); - } - } - -} diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/FeatureMethodBeanReferenceTests.java b/org.springframework.context/src/test/java/org/springframework/context/annotation/FeatureMethodBeanReferenceTests.java deleted file mode 100644 index bab82187afb..00000000000 --- a/org.springframework.context/src/test/java/org/springframework/context/annotation/FeatureMethodBeanReferenceTests.java +++ /dev/null @@ -1,76 +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 static org.hamcrest.CoreMatchers.instanceOf; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.not; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.junit.Assert.assertThat; - -import org.junit.Test; -import org.springframework.context.annotation.configuration.StubSpecification; -import org.springframework.context.config.FeatureSpecification; - -import test.beans.ITestBean; -import test.beans.TestBean; - -/** - * Tests proving that @Feature methods may reference the product of @Bean methods. - * - * @author Chris Beams - * @since 3.1 - */ -public class FeatureMethodBeanReferenceTests { - - @Test - public void test() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); - ctx.register(FeatureConfig.class, Config.class); - ctx.refresh(); - - TestBean registeredBean = ctx.getBean("testBean", TestBean.class); - TestBean proxiedBean = ctx.getBean(FeatureConfig.class).testBean; - - assertThat(registeredBean, not(instanceOf(EarlyBeanReferenceProxy.class))); - assertThat(proxiedBean, notNullValue()); - assertThat(proxiedBean, instanceOf(EarlyBeanReferenceProxy.class)); - assertThat(proxiedBean.getSpouse(), is(registeredBean.getSpouse())); - } - - - @FeatureConfiguration - static class FeatureConfig { - TestBean testBean; - - @Feature - public FeatureSpecification f(TestBean testBean) { - this.testBean = testBean; - return new StubSpecification(); - } - } - - - @Configuration - static class Config { - @Bean - public ITestBean testBean() { - return new TestBean(new TestBean("mySpouse")); - } - } - -} diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/FeatureMethodEarlyBeanProxyTests.java b/org.springframework.context/src/test/java/org/springframework/context/annotation/FeatureMethodEarlyBeanProxyTests.java deleted file mode 100644 index 62784a84a34..00000000000 --- a/org.springframework.context/src/test/java/org/springframework/context/annotation/FeatureMethodEarlyBeanProxyTests.java +++ /dev/null @@ -1,192 +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 static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.instanceOf; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.not; -import static org.junit.Assert.assertThat; - -import org.junit.Test; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.BeanFactoryAware; -import org.springframework.beans.factory.support.DefaultListableBeanFactory; -import org.springframework.context.annotation.configuration.StubSpecification; -import org.springframework.context.config.FeatureSpecification; - -import test.beans.ITestBean; -import test.beans.TestBean; - -/** - * Tests that @Bean methods referenced from within @Feature methods - * get proxied early to avoid premature instantiation of actual - * bean instances. - * - * @author Chris Beams - * @since 3.1 - */ -public class FeatureMethodEarlyBeanProxyTests { - - @Test - public void earlyProxyCreationAndBeanRegistrationLifecycle() { - AnnotationConfigApplicationContext ctx = - new AnnotationConfigApplicationContext(FeatureConfig.class); - - // - // see additional assertions in FeatureConfig#feature() - // - - // sanity check that all the bean definitions we expecting are present - assertThat(ctx.getBeanFactory().containsBeanDefinition("lazyHelperBean"), is(true)); - assertThat(ctx.getBeanFactory().containsBeanDefinition("eagerHelperBean"), is(true)); - assertThat(ctx.getBeanFactory().containsBeanDefinition("lazyPassthroughBean"), is(true)); - assertThat(ctx.getBeanFactory().containsBeanDefinition("eagerPassthroughBean"), is(true)); - - - // the lazy helper bean had methods invoked during feature method execution. it should be registered - assertThat(ctx.getBeanFactory().containsSingleton("lazyHelperBean"), is(true)); - - // the eager helper bean had methods invoked but should be registered in any case is it is non-lazy - assertThat(ctx.getBeanFactory().containsSingleton("eagerHelperBean"), is(true)); - - // the lazy passthrough bean was referenced in the feature method, but never invoked. it should not be registered - assertThat(ctx.getBeanFactory().containsSingleton("lazyPassthroughBean"), is(false)); - - // the eager passthrough bean should be registered in any case as it is non-lazy - assertThat(ctx.getBeanFactory().containsSingleton("eagerPassthroughBean"), is(true)); - - - // now actually fetch all the beans. none should be proxies - assertThat(ctx.getBean("lazyHelperBean"), not(instanceOf(EarlyBeanReferenceProxy.class))); - assertThat(ctx.getBean("eagerHelperBean"), not(instanceOf(EarlyBeanReferenceProxy.class))); - assertThat(ctx.getBean("lazyPassthroughBean"), not(instanceOf(EarlyBeanReferenceProxy.class))); - assertThat(ctx.getBean("eagerPassthroughBean"), not(instanceOf(EarlyBeanReferenceProxy.class))); - } - - - @Test - public void earlyProxyBeansMayBeInterfaceBasedOrConcrete() { - new AnnotationConfigApplicationContext(FeatureConfigReferencingNonInterfaceBeans.class); - } -} - - -@FeatureConfiguration -@Import(TestBeanConfig.class) -class FeatureConfig implements BeanFactoryAware { - private DefaultListableBeanFactory beanFactory; - - public void setBeanFactory(BeanFactory beanFactory) throws BeansException { - this.beanFactory = (DefaultListableBeanFactory)beanFactory; - } - - @Feature - public StubSpecification feature(TestBeanConfig beans) { - - assertThat( - "The @Configuration class instance itself should be an early-ref proxy", - beans, instanceOf(EarlyBeanReferenceProxy.class)); - - // invocation of @Bean methods within @Feature methods should return proxies - ITestBean lazyHelperBean = beans.lazyHelperBean(); - ITestBean eagerHelperBean = beans.eagerHelperBean(); - ITestBean lazyPassthroughBean = beans.lazyPassthroughBean(); - ITestBean eagerPassthroughBean = beans.eagerPassthroughBean(); - - assertThat(lazyHelperBean, instanceOf(EarlyBeanReferenceProxy.class)); - assertThat(eagerHelperBean, instanceOf(EarlyBeanReferenceProxy.class)); - assertThat(lazyPassthroughBean, instanceOf(EarlyBeanReferenceProxy.class)); - assertThat(eagerPassthroughBean, instanceOf(EarlyBeanReferenceProxy.class)); - - // but at this point, the proxy instances should not have - // been registered as singletons with the container. - assertThat(this.beanFactory.containsSingleton("lazyHelperBean"), is(false)); - assertThat(this.beanFactory.containsSingleton("eagerHelperBean"), is(false)); - assertThat(this.beanFactory.containsSingleton("lazyPassthroughBean"), is(false)); - assertThat(this.beanFactory.containsSingleton("eagerPassthroughBean"), is(false)); - - // invoking a method on the proxy should cause it to pass through - // to the container, instantiate the actual bean in question and - // register that actual underlying instance as a singleton. - assertThat(lazyHelperBean.getName(), equalTo("lazyHelper")); - assertThat(eagerHelperBean.getName(), equalTo("eagerHelper")); - - assertThat(this.beanFactory.containsSingleton("lazyHelperBean"), is(true)); - assertThat(this.beanFactory.containsSingleton("eagerHelperBean"), is(true)); - - // since no methods were called on the passthrough beans, they should remain - // uncreated / unregistered. - assertThat(this.beanFactory.containsSingleton("lazyPassthroughBean"), is(false)); - assertThat(this.beanFactory.containsSingleton("eagerPassthroughBean"), is(false)); - - return new StubSpecification(); - } -} - - -@Configuration -class TestBeanConfig { - - @Lazy @Bean - public ITestBean lazyHelperBean() { - return new TestBean("lazyHelper"); - } - - @Bean - public ITestBean eagerHelperBean() { - return new TestBean("eagerHelper"); - } - - @Lazy @Bean - public ITestBean lazyPassthroughBean() { - return new TestBean("lazyPassthrough"); - } - - @Bean - public ITestBean eagerPassthroughBean() { - return new TestBean("eagerPassthrough"); - } - -} - - -@FeatureConfiguration -@Import(NonInterfaceBeans.class) -class FeatureConfigReferencingNonInterfaceBeans { - @Feature - public FeatureSpecification feature1(NonInterfaceBeans beans) throws Throwable { - beans.testBean(); - return new StubSpecification(); - } - - @Feature - public FeatureSpecification feature2(TestBean testBean) throws Throwable { - return new StubSpecification(); - } -} - - -@Configuration -class NonInterfaceBeans { - @Bean - public TestBean testBean() { - return new TestBean("invalid"); - } -} - diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/FeatureMethodErrorTests.java b/org.springframework.context/src/test/java/org/springframework/context/annotation/FeatureMethodErrorTests.java deleted file mode 100644 index 10566d58918..00000000000 --- a/org.springframework.context/src/test/java/org/springframework/context/annotation/FeatureMethodErrorTests.java +++ /dev/null @@ -1,113 +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 static org.hamcrest.CoreMatchers.equalTo; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; - -import org.junit.Test; -import org.springframework.context.annotation.configuration.StubSpecification; -import org.springframework.context.config.FeatureSpecification; - -import test.beans.TestBean; - -/** - * Tests proving that @Feature methods may reference the product of @Bean methods. - * - * @author Chris Beams - * @since 3.1 - */ -public class FeatureMethodErrorTests { - - @Test - public void incorrectReturnType() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); - ctx.register(FeatureConfig.class); - try { - ctx.refresh(); - fail("expected exception"); - } catch (FeatureMethodExecutionException ex) { - assertThat(ex.getCause().getMessage(), - equalTo("Return type for @Feature method FeatureConfig.f() must be " + - "assignable to FeatureSpecification")); - } - } - - @Test - public void voidReturnType() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); - ctx.register(VoidFeatureConfig.class); - try { - ctx.refresh(); - fail("expected exception"); - } catch (FeatureMethodExecutionException ex) { - assertThat(ex.getCause().getMessage(), - equalTo("Return type for @Feature method VoidFeatureConfig.f() must be " + - "assignable to FeatureSpecification")); - } - } - - @Test - public void containsBeanMethod() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); - ctx.register(FeatureConfigWithBeanMethod.class); - try { - ctx.refresh(); - fail("expected exception"); - } catch (FeatureMethodExecutionException ex) { - assertThat(ex.getMessage(), - equalTo("@FeatureConfiguration classes must not contain @Bean-annotated methods. " + - "FeatureConfigWithBeanMethod.testBean() 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.")); - } - } - - - @FeatureConfiguration - static class FeatureConfig { - @Feature - public Object f() { - return new StubSpecification(); - } - } - - - @FeatureConfiguration - static class VoidFeatureConfig { - @Feature - public void f() { - } - } - - - @FeatureConfiguration - static class FeatureConfigWithBeanMethod { - @Feature - public FeatureSpecification f() { - return new StubSpecification(); - } - - @Bean - public TestBean testBean() { - return new TestBean(); - } - } - -} diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/FeatureMethodQualifiedBeanReferenceTests.java b/org.springframework.context/src/test/java/org/springframework/context/annotation/FeatureMethodQualifiedBeanReferenceTests.java deleted file mode 100644 index 5ea134eb330..00000000000 --- a/org.springframework.context/src/test/java/org/springframework/context/annotation/FeatureMethodQualifiedBeanReferenceTests.java +++ /dev/null @@ -1,70 +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 static org.hamcrest.CoreMatchers.equalTo; -import static org.junit.Assert.assertThat; - -import org.junit.Test; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.context.annotation.configuration.StubSpecification; -import org.springframework.context.config.FeatureSpecification; - -import test.beans.ITestBean; -import test.beans.TestBean; - -/** - * Tests proving that @Feature methods may reference beans using @Qualifier - * as a parameter annotation. - * - * @author Chris Beams - * @since 3.1 - */ -public class FeatureMethodQualifiedBeanReferenceTests { - - @Test - public void test() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); - ctx.register(Features.class, TestBeans.class); - ctx.refresh(); - } - - @FeatureConfiguration - static class Features { - - @Feature - public FeatureSpecification f(@Qualifier("testBean1") ITestBean testBean) { - assertThat(testBean.getName(), equalTo("one")); - return new StubSpecification(); - } - - } - - @Configuration - static class TestBeans { - @Bean - public ITestBean testBean1() { - return new TestBean("one"); - } - - @Bean - public ITestBean testBean2() { - return new TestBean("two"); - } - } - -} diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/FeatureMethodValueInjectionTests.java b/org.springframework.context/src/test/java/org/springframework/context/annotation/FeatureMethodValueInjectionTests.java deleted file mode 100644 index 71d0c0dd0b3..00000000000 --- a/org.springframework.context/src/test/java/org/springframework/context/annotation/FeatureMethodValueInjectionTests.java +++ /dev/null @@ -1,135 +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 static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; - -import org.junit.Test; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.configuration.StubSpecification; - -/** - * Tests ensuring that @Feature methods can accept @Value-annoted - * parameters, particularly String types. SPR-7974 revealed this - * was failing due to attempting to proxy objects of type String, - * which cannot be done. - * - * @author Chris Beams - */ -public class FeatureMethodValueInjectionTests { - - @Test - public void control() { - System.setProperty("foo", "bar"); - System.setProperty("num", "2"); - Config config = new AnnotationConfigApplicationContext(Config.class).getBean(Config.class); - System.clearProperty("foo"); - System.clearProperty("num"); - assertThat(config.foo, is("bar")); - assertThat(config.num, is(2)); - } - - @Test - public void spelValueInjection() { - System.setProperty("foo", "bar"); - new AnnotationConfigApplicationContext(SpelValueInjectionFeatureConfig.class); - System.clearProperty("foo"); - } - - @Test - public void spelIntValueInjection() { - System.setProperty("num", "5"); - new AnnotationConfigApplicationContext(SpelIntValueInjectionFeatureConfig.class); - System.clearProperty("num"); - } - - @Test - public void stringBeanInjection() { - new AnnotationConfigApplicationContext(StringBeanConfig.class, StringBeanInjectionByTypeFeatureConfig.class); - } - - @Test - public void qualifiedStringBeanInjection() { - new AnnotationConfigApplicationContext(StringBeanSubConfig.class, StringBeanInjectionByQualifierFeatureConfig.class); - } - - - @FeatureConfiguration - static class SpelValueInjectionFeatureConfig { - @Feature - public StubSpecification feature(@Value("#{environment['foo']}") String foo) { - return new StubSpecification(); - } - } - - - @FeatureConfiguration - static class SpelIntValueInjectionFeatureConfig { - @Feature - public StubSpecification feature(@Value("#{environment['num']}") int num) { - assertThat(num, is(5)); - return new StubSpecification(); - } - } - - - @Configuration - static class StringBeanConfig { - @Bean - public String stringBean() { - return "sb"; - } - } - - - @Configuration - static class StringBeanSubConfig extends StringBeanConfig { - @Bean - public String stringBean2() { - return "sb2"; - } - } - - - @FeatureConfiguration - static class StringBeanInjectionByTypeFeatureConfig { - @Feature - public StubSpecification feature(String string) { - assertThat(string, is("sb")); - return new StubSpecification(); - } - } - - - @FeatureConfiguration - static class StringBeanInjectionByQualifierFeatureConfig { - @Feature - public StubSpecification feature(@Qualifier("stringBean2") String string) { - assertThat(string, is("sb2")); - return new StubSpecification(); - } - } - - - @Configuration - static class Config { - @Value("#{environment['foo']}") String foo; - @Value("#{environment['num']}") int num; - } -} diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/SimpleFeatureMethodProcessingTests.java b/org.springframework.context/src/test/java/org/springframework/context/annotation/SimpleFeatureMethodProcessingTests.java deleted file mode 100644 index 247263a1a06..00000000000 --- a/org.springframework.context/src/test/java/org/springframework/context/annotation/SimpleFeatureMethodProcessingTests.java +++ /dev/null @@ -1,64 +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 static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; - -import org.junit.Test; -import org.springframework.context.annotation.configuration.StubSpecification; -import org.springframework.context.config.SpecificationContext; -import org.springframework.context.config.FeatureSpecification; -import org.springframework.context.config.FeatureSpecificationExecutor; -import org.springframework.util.Assert; - -/** - * Simple tests to ensure that @Feature methods are invoked and that the - * resulting returned {@link FeatureSpecification} object is delegated to - * the correct {@link FeatureSpecificationExecutor}. - * - * @author Chris Beams - * @since 3.1 - */ -public class SimpleFeatureMethodProcessingTests { - - @Test - public void test() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); - ctx.register(FeatureConfig.class); - assertThat(MySpecificationExecutor.executeMethodWasCalled, is(false)); - ctx.refresh(); - assertThat(MySpecificationExecutor.executeMethodWasCalled, is(true)); - } - - @FeatureConfiguration - static class FeatureConfig { - @Feature - public FeatureSpecification f() { - return new StubSpecification(MySpecificationExecutor.class); - } - } - - static class MySpecificationExecutor implements FeatureSpecificationExecutor { - static boolean executeMethodWasCalled = false; - public void execute(FeatureSpecification spec, SpecificationContext specificationContext) { - Assert.state(executeMethodWasCalled == false); - executeMethodWasCalled = true; - } - } - -} diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/configuration/FeatureMethodAndAutowiredFieldTests.xml b/org.springframework.context/src/test/java/org/springframework/context/annotation/configuration/FeatureMethodAndAutowiredFieldTests.xml deleted file mode 100644 index 0418dc8251a..00000000000 --- a/org.springframework.context/src/test/java/org/springframework/context/annotation/configuration/FeatureMethodAndAutowiredFieldTests.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/configuration/FeatureMethodLifecycleIssueTestSuite.java b/org.springframework.context/src/test/java/org/springframework/context/annotation/configuration/FeatureMethodLifecycleIssueTestSuite.java deleted file mode 100644 index 9c057cceb0b..00000000000 --- a/org.springframework.context/src/test/java/org/springframework/context/annotation/configuration/FeatureMethodLifecycleIssueTestSuite.java +++ /dev/null @@ -1,37 +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.configuration; - -import org.junit.runner.RunWith; -import org.junit.runners.Suite; -import org.junit.runners.Suite.SuiteClasses; - -import org.springframework.context.annotation.FeatureMethodEarlyBeanProxyTests; - -/** - * Test suite that groups all tests related to @Feature method lifecycle issues. - * - * @author Chris Beams - */ -@RunWith(Suite.class) -@SuiteClasses({ - FeatureMethodEarlyBeanProxyTests.class, - ConfigurationClassWithPlaceholderConfigurerBeanTests.class -}) -public class FeatureMethodLifecycleIssueTestSuite { - -} diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/configuration/StubSpecification.java b/org.springframework.context/src/test/java/org/springframework/context/annotation/configuration/StubSpecification.java deleted file mode 100644 index 53ed3dad757..00000000000 --- a/org.springframework.context/src/test/java/org/springframework/context/annotation/configuration/StubSpecification.java +++ /dev/null @@ -1,46 +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.configuration; - -import org.springframework.beans.factory.parsing.ProblemCollector; -import org.springframework.context.config.AbstractFeatureSpecification; -import org.springframework.context.config.FeatureSpecification; -import org.springframework.context.config.FeatureSpecificationExecutor; -import org.springframework.context.config.SpecificationContext; - -public class StubSpecification extends AbstractFeatureSpecification { - - public StubSpecification() { - this(StubSpecificationExecutor.class); - } - - public StubSpecification(Class excecutorType) { - super(excecutorType); - } - - @Override - protected void doValidate(ProblemCollector problems) { - } - -} - -class StubSpecificationExecutor implements FeatureSpecificationExecutor { - - public void execute(FeatureSpecification spec, SpecificationContext specificationContext) { - } - -} diff --git a/org.springframework.integration-tests/src/test/java/org/springframework/context/annotation/FeatureTestSuite.java b/org.springframework.integration-tests/src/test/java/org/springframework/context/annotation/FeatureTestSuite.java deleted file mode 100644 index 5531b325d2c..00000000000 --- a/org.springframework.integration-tests/src/test/java/org/springframework/context/annotation/FeatureTestSuite.java +++ /dev/null @@ -1,80 +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; - -/** - * Tests directly or indirectly related to {@link FeatureConfiguration} class and - * {@link Feature} method processing. - * - * @author Chris Beams - * @since 3.1 - * - * commented due to classpath visibility differences between Eclipse - * and Ant/Ivy at the command line. Eclipse can see classes across - * project test folders, Ant/Ivy are not configured to do so. Uncomment - * as necessary when doing @Feature-related work. -import org.junit.runner.RunWith; -import org.junit.runners.Suite; -import org.junit.runners.Suite.SuiteClasses; -import org.springframework.transaction.TxNamespaceHandlerTests; -import org.springframework.transaction.annotation.AnnotationTransactionNamespaceHandlerTests; -import org.springframework.transaction.annotation.TxAnnotationDrivenFeatureTests; -import org.springframework.transaction.config.AnnotationDrivenTests; -import org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParserTests; -import org.springframework.web.servlet.config.MvcAnnotationDrivenFeatureTests; -import org.springframework.web.servlet.config.MvcDefaultServletHandlerTests; -import org.springframework.web.servlet.config.MvcNamespaceTests; -import org.springframework.web.servlet.config.MvcResourcesTests; -import org.springframework.web.servlet.config.MvcViewControllersTests; - -@RunWith(Suite.class) -@SuiteClasses({ - EarlyBeanReferenceProxyCreatorTests.class, - SimpleFeatureMethodProcessingTests.class, - BeanFactoryAwareFeatureConfigurationTests.class, - FeatureMethodBeanReferenceTests.class, - FeatureMethodQualifiedBeanReferenceTests.class, - FeatureMethodErrorTests.class, - FeatureConfigurationClassTests.class, - FeatureMethodEarlyBeanProxyTests.class, - FeatureConfigurationImportTests.class, - FeatureConfigurationImportResourceTests.class, - - // context:component-scan related - ComponentScanFeatureTests.class, - ComponentScanSpecTests.class, - ComponentScanAnnotationTests.class, - ComponentScanAnnotationIntegrationTests.class, - - // tx-related - TxAnnotationDrivenFeatureTests.class, - TxNamespaceHandlerTests.class, - AnnotationTransactionNamespaceHandlerTests.class, - AnnotationDrivenTests.class, - - // mvc-related - AnnotationDrivenBeanDefinitionParserTests.class, - MvcAnnotationDrivenFeatureTests.class, - MvcViewControllersTests.class, - MvcResourcesTests.class, - MvcDefaultServletHandlerTests.class, - MvcNamespaceTests.class -}) -*/ -public class FeatureTestSuite { - -} \ No newline at end of file diff --git a/org.springframework.transaction/src/main/java/org/springframework/transaction/config/AnnotationDrivenBeanDefinitionParser.java b/org.springframework.transaction/src/main/java/org/springframework/transaction/config/AnnotationDrivenBeanDefinitionParser.java index f4b1de641d7..f226115b6d3 100644 --- a/org.springframework.transaction/src/main/java/org/springframework/transaction/config/AnnotationDrivenBeanDefinitionParser.java +++ b/org.springframework.transaction/src/main/java/org/springframework/transaction/config/AnnotationDrivenBeanDefinitionParser.java @@ -16,7 +16,15 @@ package org.springframework.transaction.config; +import org.w3c.dom.Element; + import org.springframework.aop.config.AopNamespaceUtils; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.parsing.BeanComponentDefinition; +import org.springframework.beans.factory.parsing.CompositeComponentDefinition; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.context.config.AbstractSpecificationBeanDefinitionParser; import org.springframework.context.config.FeatureSpecification; @@ -40,7 +48,7 @@ import org.w3c.dom.Element; * @since 2.0 * @see TxAnnotationDriven */ -class AnnotationDrivenBeanDefinitionParser extends AbstractSpecificationBeanDefinitionParser { +class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser { /** * The bean name of the internally managed transaction advisor (mode="proxy"). diff --git a/org.springframework.transaction/src/main/java/org/springframework/transaction/config/JtaTransactionManagerBeanDefinitionParser.java b/org.springframework.transaction/src/main/java/org/springframework/transaction/config/JtaTransactionManagerBeanDefinitionParser.java index fbc190e4935..f90ca8b6b77 100644 --- a/org.springframework.transaction/src/main/java/org/springframework/transaction/config/JtaTransactionManagerBeanDefinitionParser.java +++ b/org.springframework.transaction/src/main/java/org/springframework/transaction/config/JtaTransactionManagerBeanDefinitionParser.java @@ -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. @@ -31,7 +31,7 @@ import org.springframework.util.ClassUtils; * @author Christian Dupuis * @since 2.5 */ -class JtaTransactionManagerBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { +public class JtaTransactionManagerBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { private static final String WEBLOGIC_JTA_TRANSACTION_MANAGER_CLASS_NAME = "org.springframework.transaction.jta.WebLogicJtaTransactionManager"; @@ -74,7 +74,7 @@ class JtaTransactionManagerBeanDefinitionParser extends AbstractSingleBeanDefini @Override protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) { - return TxAnnotationDriven.DEFAULT_TRANSACTION_MANAGER_BEAN_NAME; + return TxNamespaceHandler.DEFAULT_TRANSACTION_MANAGER_BEAN_NAME; } } diff --git a/org.springframework.transaction/src/main/java/org/springframework/transaction/config/TxAdviceBeanDefinitionParser.java b/org.springframework.transaction/src/main/java/org/springframework/transaction/config/TxAdviceBeanDefinitionParser.java index a8a88ca5993..7883b719e9d 100644 --- a/org.springframework.transaction/src/main/java/org/springframework/transaction/config/TxAdviceBeanDefinitionParser.java +++ b/org.springframework.transaction/src/main/java/org/springframework/transaction/config/TxAdviceBeanDefinitionParser.java @@ -48,8 +48,6 @@ import org.springframework.util.xml.DomUtils; */ class TxAdviceBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { - private static final String TRANSACTION_MANAGER_ATTRIBUTE = "transaction-manager"; - private static final String METHOD_ELEMENT = "method"; private static final String METHOD_NAME_ATTRIBUTE = "name"; @@ -76,7 +74,7 @@ class TxAdviceBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { @Override protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { - builder.addPropertyReference("transactionManager", element.getAttribute(TRANSACTION_MANAGER_ATTRIBUTE)); + builder.addPropertyReference("transactionManager", TxNamespaceHandler.getTransactionManagerName(element)); List txAttributes = DomUtils.getChildElementsByTagName(element, ATTRIBUTES_ELEMENT); if (txAttributes.size() > 1) { diff --git a/org.springframework.transaction/src/main/java/org/springframework/transaction/config/TxAnnotationDriven.java b/org.springframework.transaction/src/main/java/org/springframework/transaction/config/TxAnnotationDriven.java deleted file mode 100644 index 29bacea94f4..00000000000 --- a/org.springframework.transaction/src/main/java/org/springframework/transaction/config/TxAnnotationDriven.java +++ /dev/null @@ -1,198 +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.transaction.config; - -import org.springframework.beans.factory.parsing.ProblemCollector; -import org.springframework.context.config.AbstractFeatureSpecification; -import org.springframework.context.config.AdviceMode; -import org.springframework.context.config.FeatureSpecificationExecutor; -import org.springframework.transaction.PlatformTransactionManager; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.util.Assert; -import org.springframework.util.ObjectUtils; -import org.springframework.util.StringUtils; - -/** - * TODO SPR-7420: document - * - * @author Chris Beams - * @since 3.1 - */ -public final class TxAnnotationDriven extends AbstractFeatureSpecification { - - static final String DEFAULT_TRANSACTION_MANAGER_BEAN_NAME = "transactionManager"; - - private static final Class EXECUTOR_TYPE = TxAnnotationDrivenExecutor.class; - - private Object txManager = null; - - private Object order = null; - - private Boolean proxyTargetClass = false; - - private Object mode = AdviceMode.PROXY; - - /** - * Create a {@code TxAnnotationDriven} specification assumes the presence of a - * {@link PlatformTransactionManager} bean named {@value #DEFAULT_TRANSACTION_MANAGER_BEAN_NAME}. - * - *

See the alternate constructors defined here if your transaction manager does - * not follow this default naming or you wish to refer to it by bean instance rather - * than by bean name. - * @see #TxAnnotationDriven(String) - * @see #TxAnnotationDriven(PlatformTransactionManager) - */ - public TxAnnotationDriven() { - this(DEFAULT_TRANSACTION_MANAGER_BEAN_NAME); - } - - /** - * Create a new {@code TxAnnotationDriven} specification that will use the specified - * transaction manager bean name. - * - * @param txManagerBeanName name of {@link PlatformTransactionManager} bean or a - * ${placeholder} or SpEL #{expression} resolving to bean name. If {@code null}, - * falls back to default value of {@value #DEFAULT_TRANSACTION_MANAGER_BEAN_NAME}. - */ - public TxAnnotationDriven(String txManagerBeanName) { - super(EXECUTOR_TYPE); - this.txManager = txManagerBeanName != null ? - txManagerBeanName : - DEFAULT_TRANSACTION_MANAGER_BEAN_NAME; - } - - /** - * Create a new TxAnnotationDriven specification that will use the specified transaction - * manager. - * - * @param txManager the {@link PlatformTransactionManager} bean to use. Must not be {@code null}. - */ - public TxAnnotationDriven(PlatformTransactionManager txManager) { - super(EXECUTOR_TYPE); - Assert.notNull(txManager, "transaction manager must not be null"); - this.txManager = txManager; - } - - /** - * Return the transaction manager to use. May be a {@link PlatformTransactionManager} - * instance or a String representing the bean name or a placeholder or SpEL expression - * that resolves to the bean name. - */ - Object transactionManager() { - return this.txManager; - } - - /** - * Indicate how transactional advice should be applied. - * @see AdviceMode - */ - public TxAnnotationDriven mode(AdviceMode mode) { - this.mode = mode; - return this; - } - - /** - * Indicate how transactional advice should be applied. - * @param name matching one of the labels in the AdviceMode enum; - * placeholder and SpEL expressions are not allowed. - * @see AdviceMode - */ - TxAnnotationDriven mode(String mode) { - if (StringUtils.hasText(mode)) { - this.mode = mode; - } - return this; - } - - /** - * Return how transactional advice should be applied. - */ - AdviceMode mode() { - if (this.mode instanceof AdviceMode) { - return (AdviceMode)this.mode; - } - if (this.mode instanceof String) { - return ObjectUtils.caseInsensitiveValueOf(AdviceMode.values(), (String)this.mode); - } - // TODO SPR-7420: deal with in validate & raise problem - throw new IllegalStateException( - "invalid type for field 'mode' (must be of type AdviceMode or String): " - + this.mode.getClass().getName()); - } - - /** - * Indicate whether class-based (CGLIB) proxies are to be created as opposed - * to standard Java interface-based proxies. - * - *

Note: Class-based proxies require the {@link Transactional @Transactional} - * annotation to be defined on the concrete class. Annotations in interfaces will - * not work in that case (they will rather only work with interface-based proxies)! - */ - public TxAnnotationDriven proxyTargetClass(Boolean proxyTargetClass) { - this.proxyTargetClass = proxyTargetClass; - return this; - } - - /** - * Return whether class-based (CGLIB) proxies are to be created as opposed - * to standard Java interface-based proxies. - */ - Boolean proxyTargetClass() { - return this.proxyTargetClass; - } - - /** - * Indicate the ordering of the execution of the transaction advisor - * when multiple advice executes at a specific joinpoint. The default is - * {@code null}, indicating that default ordering should be used. - */ - public TxAnnotationDriven order(int order) { - this.order = order; - return this; - } - - /** - * Indicate the ordering of the execution of the transaction advisor - * when multiple advice executes at a specific joinpoint. The default is - * {@code null}, indicating that default ordering should be used. - */ - public TxAnnotationDriven order(String order) { - if (StringUtils.hasText(order)) { - this.order = order; - } - return this; - } - - /** - * Return the ordering of the execution of the transaction advisor - * when multiple advice executes at a specific joinpoint. May return - * {@code null}, indicating that default ordering should be used. - */ - Object order() { - return this.order; - } - - @Override - protected void doValidate(ProblemCollector problems) { - if (this.mode instanceof String) { - if (!ObjectUtils.containsConstant(AdviceMode.values(), (String)this.mode)) { - problems.error("no such mode name: " + this.mode); - } - } - } - -} \ No newline at end of file diff --git a/org.springframework.transaction/src/main/java/org/springframework/transaction/config/TxAnnotationDrivenExecutor.java b/org.springframework.transaction/src/main/java/org/springframework/transaction/config/TxAnnotationDrivenExecutor.java deleted file mode 100644 index c4f328986ed..00000000000 --- a/org.springframework.transaction/src/main/java/org/springframework/transaction/config/TxAnnotationDrivenExecutor.java +++ /dev/null @@ -1,139 +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.transaction.config; - -import org.springframework.aop.config.AopNamespaceUtils; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.config.RuntimeBeanReference; -import org.springframework.beans.factory.parsing.BeanComponentDefinition; -import org.springframework.beans.factory.parsing.ComponentRegistrar; -import org.springframework.beans.factory.parsing.CompositeComponentDefinition; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.beans.factory.support.RootBeanDefinition; -import org.springframework.context.config.AbstractSpecificationExecutor; -import org.springframework.context.config.SpecificationContext; -import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource; -import org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor; -import org.springframework.transaction.interceptor.TransactionInterceptor; -import org.springframework.util.Assert; - -/** - * TODO SPR-7420: document - * - * @author Chris Beams - * @since 3.1 - */ -final class TxAnnotationDrivenExecutor extends AbstractSpecificationExecutor { - - /** - * The bean name of the internally managed transaction advisor (used when mode == PROXY). - */ - public static final String TRANSACTION_ADVISOR_BEAN_NAME = - "org.springframework.transaction.config.internalTransactionAdvisor"; - - /** - * The bean name of the internally managed transaction aspect (used when mode == ASPECTJ). - */ - public static final String TRANSACTION_ASPECT_BEAN_NAME = - "org.springframework.transaction.config.internalTransactionAspect"; - - private static final String TRANSACTION_ASPECT_CLASS_NAME = - "org.springframework.transaction.aspectj.AnnotationTransactionAspect"; - - - @Override - protected void doExecute(TxAnnotationDriven txSpec, SpecificationContext specificationContext) { - BeanDefinitionRegistry registry = specificationContext.getRegistry(); - ComponentRegistrar registrar = specificationContext.getRegistrar(); - switch (txSpec.mode()) { - case ASPECTJ: - registerTransactionAspect(txSpec, registry, registrar); - break; - case PROXY: - AopAutoProxyConfigurer.configureAutoProxyCreator(txSpec, registry, registrar); - break; - default: - throw new IllegalArgumentException( - String.format("AdviceMode %s is not supported", txSpec.mode())); - } - } - - private void registerTransactionAspect(TxAnnotationDriven spec, BeanDefinitionRegistry registry, ComponentRegistrar registrar) { - if (!registry.containsBeanDefinition(TRANSACTION_ASPECT_BEAN_NAME)) { - RootBeanDefinition def = new RootBeanDefinition(); - def.setBeanClassName(TRANSACTION_ASPECT_CLASS_NAME); - def.setFactoryMethodName("aspectOf"); - registerTransactionManager(spec, def); - registrar.registerBeanComponent(new BeanComponentDefinition(def, TRANSACTION_ASPECT_BEAN_NAME)); - } - } - - private static void registerTransactionManager(TxAnnotationDriven spec, BeanDefinition def) { - Object txManager = spec.transactionManager(); - Assert.notNull(txManager, "transactionManager must be specified"); - if (txManager instanceof String) { - def.getPropertyValues().add("transactionManagerBeanName", txManager); - } else { - def.getPropertyValues().add("transactionManager", txManager); - } - } - - /** - * Inner class to just introduce an AOP framework dependency when actually in proxy mode. - */ - private static class AopAutoProxyConfigurer { - - public static void configureAutoProxyCreator(TxAnnotationDriven txSpec, BeanDefinitionRegistry registry, ComponentRegistrar registrar) { - Object source = txSpec.source(); - AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(registry, registrar, source, txSpec.proxyTargetClass()); - - if (!registry.containsBeanDefinition(TRANSACTION_ADVISOR_BEAN_NAME)) { - - // Create the TransactionAttributeSource definition. - RootBeanDefinition sourceDef = new RootBeanDefinition(AnnotationTransactionAttributeSource.class); - sourceDef.setSource(source); - sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - String sourceName = registrar.registerWithGeneratedName(sourceDef); - - // Create the TransactionInterceptor definition. - RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class); - interceptorDef.setSource(source); - interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - registerTransactionManager(txSpec, interceptorDef); - interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName)); - String interceptorName = registrar.registerWithGeneratedName(interceptorDef); - - // Create the TransactionAttributeSourceAdvisor definition. - RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class); - advisorDef.setSource(source); - advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - advisorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName)); - advisorDef.getPropertyValues().add("adviceBeanName", interceptorName); - if (txSpec.order() != null) { - advisorDef.getPropertyValues().add("order", txSpec.order()); - } - registry.registerBeanDefinition(TRANSACTION_ADVISOR_BEAN_NAME, advisorDef); - - CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(txSpec.sourceName(), source); - compositeDef.addNestedComponent(new BeanComponentDefinition(sourceDef, sourceName)); - compositeDef.addNestedComponent(new BeanComponentDefinition(interceptorDef, interceptorName)); - compositeDef.addNestedComponent(new BeanComponentDefinition(advisorDef, TRANSACTION_ADVISOR_BEAN_NAME)); - registrar.registerComponent(compositeDef); - } - } - } -} diff --git a/org.springframework.transaction/src/main/java/org/springframework/transaction/config/TxNamespaceHandler.java b/org.springframework.transaction/src/main/java/org/springframework/transaction/config/TxNamespaceHandler.java index bdf376f2473..ac657898304 100644 --- a/org.springframework.transaction/src/main/java/org/springframework/transaction/config/TxNamespaceHandler.java +++ b/org.springframework.transaction/src/main/java/org/springframework/transaction/config/TxNamespaceHandler.java @@ -39,6 +39,17 @@ import org.springframework.beans.factory.xml.NamespaceHandlerSupport; */ public class TxNamespaceHandler extends NamespaceHandlerSupport { + static final String TRANSACTION_MANAGER_ATTRIBUTE = "transaction-manager"; + + static final String DEFAULT_TRANSACTION_MANAGER_BEAN_NAME = "transactionManager"; + + + static String getTransactionManagerName(Element element) { + return (element.hasAttribute(TRANSACTION_MANAGER_ATTRIBUTE) ? + element.getAttribute(TRANSACTION_MANAGER_ATTRIBUTE) : DEFAULT_TRANSACTION_MANAGER_BEAN_NAME); + } + + public void init() { registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser()); registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser()); diff --git a/org.springframework.transaction/src/test/java/org/springframework/transaction/annotation/TxAnnotationDrivenFeatureTests.java b/org.springframework.transaction/src/test/java/org/springframework/transaction/annotation/TxAnnotationDrivenFeatureTests.java deleted file mode 100644 index 7071426d260..00000000000 --- a/org.springframework.transaction/src/test/java/org/springframework/transaction/annotation/TxAnnotationDrivenFeatureTests.java +++ /dev/null @@ -1,147 +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.transaction.annotation; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; - -import java.util.Map; - -import org.junit.Test; -import org.springframework.aop.support.AopUtils; -import org.springframework.beans.factory.CannotLoadBeanClassException; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Feature; -import org.springframework.context.annotation.FeatureConfiguration; -import org.springframework.context.config.AdviceMode; -import org.springframework.stereotype.Service; -import org.springframework.transaction.CallCountingTransactionManager; -import org.springframework.transaction.PlatformTransactionManager; -import org.springframework.transaction.annotation.AnnotationTransactionNamespaceHandlerTests.TransactionalTestBean; -import org.springframework.transaction.config.TxAnnotationDriven; - -/** - * Integration tests for {@link TxAnnotationDriven} support within @Configuration - * classes. Adapted from original tx: namespace tests at - * {@link AnnotationTransactionNamespaceHandlerTests}. - * - * @author Chris Beams - * @since 3.1 - */ -public class TxAnnotationDrivenFeatureTests { - @Test - public void transactionProxyIsCreated() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); - ctx.register(TxFeature.class, TxManagerConfig.class); - ctx.refresh(); - TransactionalTestBean bean = ctx.getBean(TransactionalTestBean.class); - assertThat("testBean is not a proxy", AopUtils.isAopProxy(bean), is(true)); - Map services = ctx.getBeansWithAnnotation(Service.class); - assertThat("Stereotype annotation not visible", services.containsKey("testBean"), is(true)); - } - - @Test - public void txManagerIsResolvedOnInvocationOfTransactionalMethod() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); - ctx.register(TxFeature.class, TxManagerConfig.class); - ctx.refresh(); - TransactionalTestBean bean = ctx.getBean(TransactionalTestBean.class); - - // invoke a transactional method, causing the PlatformTransactionManager bean to be resolved. - bean.findAllFoos(); - } - - @Test - public void txManagerIsResolvedCorrectlyWhenMultipleManagersArePresent() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); - ctx.register(TxFeature.class, MultiTxManagerConfig.class); - ctx.refresh(); - TransactionalTestBean bean = ctx.getBean(TransactionalTestBean.class); - - // invoke a transactional method, causing the PlatformTransactionManager bean to be resolved. - bean.findAllFoos(); - } - - /** - * A cheap test just to prove that in ASPECTJ mode, the AnnotationTransactionAspect does indeed - * get loaded -- or in this case, attempted to be loaded at which point the test fails. - */ - @Test - public void proxyTypeAspectJCausesRegistrationOfAnnotationTransactionAspect() { - try { - new AnnotationConfigApplicationContext(TxWithAspectJFeature.class, TxManagerConfig.class); - fail("should have thrown CNFE when trying to load AnnotationTransactionAspect. " + - "Do you actually have org.springframework.aspects on the classpath?"); - } catch (CannotLoadBeanClassException ex) { - ClassNotFoundException cause = (ClassNotFoundException) ex.getCause(); - assertThat(cause.getMessage(), equalTo("org.springframework.transaction.aspectj.AnnotationTransactionAspect")); - } - } - -} - -@FeatureConfiguration -class TxFeature { - - @Feature - public TxAnnotationDriven tx(TxManagerConfig txManagerConfig) { - return new TxAnnotationDriven(txManagerConfig.txManager()); - } -} - - -@FeatureConfiguration -class TxWithAspectJFeature { - - @Feature - public TxAnnotationDriven tx(PlatformTransactionManager txManager) { - return new TxAnnotationDriven(txManager).mode(AdviceMode.ASPECTJ); - } - -} - - -@Configuration -class TxManagerConfig { - - @Bean - public TransactionalTestBean testBean() { - return new TransactionalTestBean(); - } - - @Bean - public PlatformTransactionManager txManager() { - return new CallCountingTransactionManager(); - } - -} - - -@Configuration -class MultiTxManagerConfig extends TxManagerConfig { - - @Bean - public PlatformTransactionManager txManager2() { - return new CallCountingTransactionManager(); - } - -} - diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/AbstractHttpRequestHandlerBeanDefinitionParser.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/AbstractHttpRequestHandlerBeanDefinitionParser.java new file mode 100644 index 00000000000..13f10cf673b --- /dev/null +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/AbstractHttpRequestHandlerBeanDefinitionParser.java @@ -0,0 +1,57 @@ +/* + * Copyright 2002-2010 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.web.servlet.config; + +import org.w3c.dom.Element; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.parsing.BeanComponentDefinition; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.beans.factory.xml.BeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter; + +/** + * Abstract base class for {@link BeanDefinitonParser}s that register an HttpRequestHandler. + * + * @author Jeremy Grelle + * @since 3.0.4 + */ +abstract class AbstractHttpRequestHandlerBeanDefinitionParser implements BeanDefinitionParser{ + + private static final String HANDLER_ADAPTER_BEAN_NAME = "org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"; + + public BeanDefinition parse(Element element, ParserContext parserContext) { + Object source = parserContext.extractSource(element); + registerHandlerAdapterIfNecessary(parserContext, source); + doParse(element, parserContext); + return null; + } + + public abstract void doParse(Element element, ParserContext parserContext); + + private void registerHandlerAdapterIfNecessary(ParserContext parserContext, Object source) { + if (!parserContext.getRegistry().containsBeanDefinition(HANDLER_ADAPTER_BEAN_NAME)) { + RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(HttpRequestHandlerAdapter.class); + handlerAdapterDef.setSource(source); + handlerAdapterDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + parserContext.getRegistry().registerBeanDefinition(HANDLER_ADAPTER_BEAN_NAME, handlerAdapterDef); + parserContext.registerComponent(new BeanComponentDefinition(handlerAdapterDef, HANDLER_ADAPTER_BEAN_NAME)); + } + } + +} diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParser.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParser.java index ad4885a8453..ebfb201dc32 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParser.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2010 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,65 +16,265 @@ package org.springframework.web.servlet.config; -import java.util.ArrayList; import java.util.List; +import org.w3c.dom.Element; + +import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionHolder; +import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.parsing.BeanComponentDefinition; +import org.springframework.beans.factory.parsing.CompositeComponentDefinition; import org.springframework.beans.factory.support.ManagedList; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.context.config.AbstractSpecificationBeanDefinitionParser; -import org.springframework.context.config.FeatureSpecification; +import org.springframework.core.convert.ConversionService; +import org.springframework.format.support.FormattingConversionServiceFactoryBean; +import org.springframework.http.converter.ByteArrayHttpMessageConverter; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.ResourceHttpMessageConverter; +import org.springframework.http.converter.StringHttpMessageConverter; +import org.springframework.http.converter.feed.AtomFeedHttpMessageConverter; +import org.springframework.http.converter.feed.RssChannelHttpMessageConverter; +import org.springframework.http.converter.json.MappingJacksonHttpMessageConverter; +import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter; +import org.springframework.http.converter.xml.SourceHttpMessageConverter; +import org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter; import org.springframework.util.ClassUtils; import org.springframework.util.xml.DomUtils; +import org.springframework.validation.Validator; +import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; +import org.springframework.web.bind.support.ConfigurableWebBindingInitializer; import org.springframework.web.bind.support.WebArgumentResolver; +import org.springframework.web.servlet.handler.ConversionServiceExposingInterceptor; +import org.springframework.web.servlet.handler.MappedInterceptor; +import org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMethodAdapter; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMethodExceptionResolver; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMethodMapping; import org.springframework.web.servlet.mvc.method.annotation.support.ServletWebArgumentResolverAdapter; -import org.w3c.dom.Element; +import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver; /** - * {@link BeanDefinitionParser} that parses the {@code annotation-driven} element - * to configure a Spring MVC web application. + * {@link BeanDefinitionParser} that parses the {@code annotation-driven} element to configure a Spring MVC web + * application. * + *

Responsible for: + *

    + *
  1. Registering a DefaultAnnotationHandlerMapping bean for mapping HTTP Servlet Requests to @Controller methods + * using @RequestMapping annotations. + *
  2. Registering a AnnotationMethodHandlerAdapter bean for invoking annotated @Controller methods. + * Will configure the HandlerAdapter's webBindingInitializer property for centrally configuring + * {@code @Controller} {@code DataBinder} instances: + *
      + *
    • Configures the conversionService if specified, otherwise defaults to a fresh {@link ConversionService} instance + * created by the default {@link FormattingConversionServiceFactoryBean}. + *
    • Configures the validator if specified, otherwise defaults to a fresh {@link Validator} instance created by the + * default {@link LocalValidatorFactoryBean} if the JSR-303 API is present on the classpath. + *
    • Configures standard {@link org.springframework.http.converter.HttpMessageConverter HttpMessageConverters}, + * including the {@link Jaxb2RootElementHttpMessageConverter} if JAXB2 is present on the classpath, and + * the {@link MappingJacksonHttpMessageConverter} if Jackson is present on the classpath. + *
    + *
+ * + * @author Keith Donald + * @author Juergen Hoeller + * @author Arjen Poutsma * @author Rossen Stoyanchev - * @author Chris Beams * @since 3.0 - * @see MvcAnnotationDriven - * @see MvcAnnotationDrivenExecutor */ -class AnnotationDrivenBeanDefinitionParser extends AbstractSpecificationBeanDefinitionParser { +class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser { - /** - * Parses the {@code } tag. - */ - @Override - protected FeatureSpecification doParse(Element element, ParserContext parserContext) { - MvcAnnotationDriven spec = new MvcAnnotationDriven(); + private static final boolean jsr303Present = ClassUtils.isPresent( + "javax.validation.Validator", AnnotationDrivenBeanDefinitionParser.class.getClassLoader()); + + private static final boolean jaxb2Present = + ClassUtils.isPresent("javax.xml.bind.Binder", AnnotationDrivenBeanDefinitionParser.class.getClassLoader()); + + private static final boolean jacksonPresent = + ClassUtils.isPresent("org.codehaus.jackson.map.ObjectMapper", AnnotationDrivenBeanDefinitionParser.class.getClassLoader()) && + ClassUtils.isPresent("org.codehaus.jackson.JsonGenerator", AnnotationDrivenBeanDefinitionParser.class.getClassLoader()); + + private static boolean romePresent = + ClassUtils.isPresent("com.sun.syndication.feed.WireFeed", AnnotationDrivenBeanDefinitionParser.class.getClassLoader()); + + + public BeanDefinition parse(Element element, ParserContext parserContext) { + Object source = parserContext.extractSource(element); + + CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source); + parserContext.pushContainingComponent(compDefinition); + + RootBeanDefinition methodMappingDef = new RootBeanDefinition(RequestMappingHandlerMethodMapping.class); + methodMappingDef.setSource(source); + methodMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + methodMappingDef.getPropertyValues().add("order", 0); + String methodMappingName = parserContext.getReaderContext().registerWithGeneratedName(methodMappingDef); + + RuntimeBeanReference conversionService = getConversionService(element, source, parserContext); + RuntimeBeanReference validator = getValidator(element, source, parserContext); + RuntimeBeanReference messageCodesResolver = getMessageCodesResolver(element, source, parserContext); + + RootBeanDefinition bindingDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class); + bindingDef.setSource(source); + bindingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + bindingDef.getPropertyValues().add("conversionService", conversionService); + bindingDef.getPropertyValues().add("validator", validator); + bindingDef.getPropertyValues().add("messageCodesResolver", messageCodesResolver); + + ManagedList messageConverters = getMessageConverters(element, source, parserContext); + ManagedList argumentResolvers = getArgumentResolvers(element, source, parserContext); + + RootBeanDefinition methodAdapterDef = new RootBeanDefinition(RequestMappingHandlerMethodAdapter.class); + methodAdapterDef.setSource(source); + methodAdapterDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + methodAdapterDef.getPropertyValues().add("webBindingInitializer", bindingDef); + methodAdapterDef.getPropertyValues().add("messageConverters", messageConverters); + if (argumentResolvers != null) { + methodAdapterDef.getPropertyValues().add("customArgumentResolvers", argumentResolvers); + } + String methodAdapterName = parserContext.getReaderContext().registerWithGeneratedName(methodAdapterDef); + + RootBeanDefinition csInterceptorDef = new RootBeanDefinition(ConversionServiceExposingInterceptor.class); + csInterceptorDef.setSource(source); + csInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, conversionService); + RootBeanDefinition mappedCsInterceptorDef = new RootBeanDefinition(MappedInterceptor.class); + mappedCsInterceptorDef.setSource(source); + mappedCsInterceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + mappedCsInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, (Object) null); + mappedCsInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(1, csInterceptorDef); + String mappedInterceptorName = parserContext.getReaderContext().registerWithGeneratedName(mappedCsInterceptorDef); + + RootBeanDefinition methodExceptionResolver = new RootBeanDefinition(RequestMappingHandlerMethodExceptionResolver.class); + methodExceptionResolver.setSource(source); + methodExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + methodExceptionResolver.getPropertyValues().add("messageConverters", messageConverters); + methodExceptionResolver.getPropertyValues().add("order", 0); + String methodExceptionResolverName = + parserContext.getReaderContext().registerWithGeneratedName(methodExceptionResolver); + + RootBeanDefinition responseStatusExceptionResolver = new RootBeanDefinition(ResponseStatusExceptionResolver.class); + responseStatusExceptionResolver.setSource(source); + responseStatusExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + responseStatusExceptionResolver.getPropertyValues().add("order", 1); + String responseStatusExceptionResolverName = + parserContext.getReaderContext().registerWithGeneratedName(responseStatusExceptionResolver); + + RootBeanDefinition defaultExceptionResolver = new RootBeanDefinition(DefaultHandlerExceptionResolver.class); + defaultExceptionResolver.setSource(source); + defaultExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + defaultExceptionResolver.getPropertyValues().add("order", 2); + String defaultExceptionResolverName = + parserContext.getReaderContext().registerWithGeneratedName(defaultExceptionResolver); + + parserContext.registerComponent(new BeanComponentDefinition(methodMappingDef, methodMappingName)); + parserContext.registerComponent(new BeanComponentDefinition(methodAdapterDef, methodAdapterName)); + parserContext.registerComponent(new BeanComponentDefinition(methodExceptionResolver, methodExceptionResolverName)); + parserContext.registerComponent(new BeanComponentDefinition(responseStatusExceptionResolver, responseStatusExceptionResolverName)); + parserContext.registerComponent(new BeanComponentDefinition(defaultExceptionResolver, defaultExceptionResolverName)); + parserContext.registerComponent(new BeanComponentDefinition(mappedCsInterceptorDef, mappedInterceptorName)); + parserContext.popAndRegisterContainingComponent(); + + return null; + } + + private RuntimeBeanReference getConversionService(Element element, Object source, ParserContext parserContext) { + RuntimeBeanReference conversionServiceRef; if (element.hasAttribute("conversion-service")) { - String conversionService = element.getAttribute("conversion-service"); - spec.conversionService(conversionService); + conversionServiceRef = new RuntimeBeanReference(element.getAttribute("conversion-service")); } + else { + RootBeanDefinition conversionDef = new RootBeanDefinition(FormattingConversionServiceFactoryBean.class); + conversionDef.setSource(source); + conversionDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + String conversionName = parserContext.getReaderContext().registerWithGeneratedName(conversionDef); + parserContext.registerComponent(new BeanComponentDefinition(conversionDef, conversionName)); + conversionServiceRef = new RuntimeBeanReference(conversionName); + } + return conversionServiceRef; + } + + private RuntimeBeanReference getValidator(Element element, Object source, ParserContext parserContext) { if (element.hasAttribute("validator")) { - spec.validator(element.getAttribute("validator")); + return new RuntimeBeanReference(element.getAttribute("validator")); } + else if (jsr303Present) { + RootBeanDefinition validatorDef = new RootBeanDefinition(LocalValidatorFactoryBean.class); + validatorDef.setSource(source); + validatorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + String validatorName = parserContext.getReaderContext().registerWithGeneratedName(validatorDef); + parserContext.registerComponent(new BeanComponentDefinition(validatorDef, validatorName)); + return new RuntimeBeanReference(validatorName); + } + else { + return null; + } + } + + private RuntimeBeanReference getMessageCodesResolver(Element element, Object source, ParserContext parserContext) { if (element.hasAttribute("message-codes-resolver")) { - spec.messageCodesResolver(element.getAttribute("message-codes-resolver")); - } - Element convertersElement = DomUtils.getChildElementByTagName(element, "message-converters"); - if (convertersElement != null) { - if (convertersElement.hasAttribute("register-defaults")) { - spec.shouldRegisterDefaultMessageConverters(Boolean.valueOf(convertersElement - .getAttribute("register-defaults"))); - } - spec.messageConverters(extractBeanSubElements(convertersElement, parserContext)); + return new RuntimeBeanReference(element.getAttribute("message-codes-resolver")); + } else { + return null; } + } + + private ManagedList getArgumentResolvers(Element element, Object source, ParserContext parserContext) { Element resolversElement = DomUtils.getChildElementByTagName(element, "argument-resolvers"); if (resolversElement != null) { - ManagedList beanDefs = extractBeanSubElements(resolversElement, parserContext); - spec.argumentResolvers(wrapWebArgumentResolverBeanDefs(beanDefs)); + ManagedList argumentResolvers = extractBeanSubElements(resolversElement, parserContext); + return wrapWebArgumentResolverBeanDefs(argumentResolvers); + } + return null; + } + + private ManagedList getMessageConverters(Element element, Object source, ParserContext parserContext) { + Element convertersElement = DomUtils.getChildElementByTagName(element, "message-converters"); + ManagedList messageConverters = new ManagedList(); + if (convertersElement != null) { + messageConverters.setSource(source); + for (Element converter : DomUtils.getChildElementsByTagName(convertersElement, "bean")) { + BeanDefinitionHolder beanDef = parserContext.getDelegate().parseBeanDefinitionElement(converter); + beanDef = parserContext.getDelegate().decorateBeanDefinitionIfRequired(converter, beanDef); + messageConverters.add(beanDef); + } } - return spec; + if (convertersElement == null || Boolean.valueOf(convertersElement.getAttribute("register-defaults"))) { + messageConverters.setSource(source); + messageConverters.add(createConverterBeanDefinition(ByteArrayHttpMessageConverter.class, source)); + + RootBeanDefinition stringConverterDef = createConverterBeanDefinition(StringHttpMessageConverter.class, + source); + stringConverterDef.getPropertyValues().add("writeAcceptCharset", false); + messageConverters.add(stringConverterDef); + + messageConverters.add(createConverterBeanDefinition(ResourceHttpMessageConverter.class, source)); + messageConverters.add(createConverterBeanDefinition(SourceHttpMessageConverter.class, source)); + messageConverters.add(createConverterBeanDefinition(XmlAwareFormHttpMessageConverter.class, source)); + if (jaxb2Present) { + messageConverters + .add(createConverterBeanDefinition(Jaxb2RootElementHttpMessageConverter.class, source)); + } + if (jacksonPresent) { + messageConverters.add(createConverterBeanDefinition(MappingJacksonHttpMessageConverter.class, source)); + } + if (romePresent) { + messageConverters.add(createConverterBeanDefinition(AtomFeedHttpMessageConverter.class, source)); + messageConverters.add(createConverterBeanDefinition(RssChannelHttpMessageConverter.class, source)); + } + } + return messageConverters; + } + + private RootBeanDefinition createConverterBeanDefinition(Class converterClass, + Object source) { + RootBeanDefinition beanDefinition = new RootBeanDefinition(converterClass); + beanDefinition.setSource(source); + beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + + return beanDefinition; } private ManagedList extractBeanSubElements(Element parentElement, ParserContext parserContext) { @@ -90,21 +290,20 @@ class AnnotationDrivenBeanDefinitionParser extends AbstractSpecificationBeanDefi private ManagedList wrapWebArgumentResolverBeanDefs(List beanDefs) { ManagedList result = new ManagedList(); - + for (BeanDefinitionHolder beanDef : beanDefs) { String className = beanDef.getBeanDefinition().getBeanClassName(); Class clazz = ClassUtils.resolveClassName(className, ClassUtils.getDefaultClassLoader()); - + if (WebArgumentResolver.class.isAssignableFrom(clazz)) { RootBeanDefinition adapter = new RootBeanDefinition(ServletWebArgumentResolverAdapter.class); adapter.getConstructorArgumentValues().addIndexedArgumentValue(0, beanDef); result.add(new BeanDefinitionHolder(adapter, beanDef.getBeanName() + "Adapter")); - } - else { + } else { result.add(beanDef); } } - + return result; } } diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/DefaultServletHandlerBeanDefinitionParser.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/DefaultServletHandlerBeanDefinitionParser.java index 7efa18b5bcb..fe60722234d 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/DefaultServletHandlerBeanDefinitionParser.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/DefaultServletHandlerBeanDefinitionParser.java @@ -16,36 +16,58 @@ package org.springframework.web.servlet.config; +import java.util.Map; + +import org.w3c.dom.Element; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.parsing.BeanComponentDefinition; +import org.springframework.beans.factory.support.ManagedMap; +import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.context.config.AbstractSpecificationBeanDefinitionParser; -import org.springframework.context.config.FeatureSpecification; import org.springframework.util.StringUtils; import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter; import org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler; -import org.w3c.dom.Element; /** * {@link BeanDefinitionParser} that parses a {@code default-servlet-handler} element to * register a {@link DefaultServletHttpRequestHandler}. Will also register a * {@link SimpleUrlHandlerMapping} for mapping resource requests, and a * {@link HttpRequestHandlerAdapter} if necessary. - * - * @author Rossen Stoyanchev - * @author Chris Beams + * + * @author Jeremy Grelle * @since 3.0.4 */ -class DefaultServletHandlerBeanDefinitionParser extends AbstractSpecificationBeanDefinitionParser { +class DefaultServletHandlerBeanDefinitionParser extends AbstractHttpRequestHandlerBeanDefinitionParser { - /** - * Parses the {@code } tag. - */ - public FeatureSpecification doParse(Element element, ParserContext parserContext) { - String defaultServletHandler = element.getAttribute("default-servlet-handler"); - return StringUtils.hasText(defaultServletHandler) ? - new MvcDefaultServletHandler(defaultServletHandler) : - new MvcDefaultServletHandler(); + @Override + public void doParse(Element element, ParserContext parserContext) { + Object source = parserContext.extractSource(element); + + String defaultServletName = element.getAttribute("default-servlet-name"); + RootBeanDefinition defaultServletHandlerDef = new RootBeanDefinition(DefaultServletHttpRequestHandler.class); + defaultServletHandlerDef.setSource(source); + defaultServletHandlerDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + if (StringUtils.hasText(defaultServletName)) { + defaultServletHandlerDef.getPropertyValues().add("defaultServletName", defaultServletName); + } + String defaultServletHandlerName = parserContext.getReaderContext().generateBeanName(defaultServletHandlerDef); + parserContext.getRegistry().registerBeanDefinition(defaultServletHandlerName, defaultServletHandlerDef); + parserContext.registerComponent(new BeanComponentDefinition(defaultServletHandlerDef, defaultServletHandlerName)); + + Map urlMap = new ManagedMap(); + urlMap.put("/**", defaultServletHandlerName); + + RootBeanDefinition handlerMappingDef = new RootBeanDefinition(SimpleUrlHandlerMapping.class); + handlerMappingDef.setSource(source); + handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + handlerMappingDef.getPropertyValues().add("urlMap", urlMap); + + String handlerMappingBeanName = parserContext.getReaderContext().generateBeanName(handlerMappingDef); + parserContext.getRegistry().registerBeanDefinition(handlerMappingBeanName, handlerMappingDef); + parserContext.registerComponent(new BeanComponentDefinition(handlerMappingDef, handlerMappingBeanName)); } } diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/InterceptorsBeanDefinitionParser.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/InterceptorsBeanDefinitionParser.java index 55f95bb9e6f..90a3afebff0 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/InterceptorsBeanDefinitionParser.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/InterceptorsBeanDefinitionParser.java @@ -18,54 +18,59 @@ package org.springframework.web.servlet.config; import java.util.List; +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.RootBeanDefinition; +import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.context.config.AbstractSpecificationBeanDefinitionParser; -import org.springframework.context.config.FeatureSpecification; import org.springframework.util.xml.DomUtils; import org.springframework.web.servlet.handler.MappedInterceptor; import org.w3c.dom.Element; /** - * {@link org.springframework.beans.factory.xml.BeanDefinitionParser} that parses - * a {@code interceptors} element to register set of {@link MappedInterceptor} - * definitions. + * {@link org.springframework.beans.factory.xml.BeanDefinitionParser} that parses a {@code interceptors} element to register + * a set of {@link MappedInterceptor} definitions. * * @author Keith Donald - * @author Rossen Stoyanchev - * * @since 3.0 */ -class InterceptorsBeanDefinitionParser extends AbstractSpecificationBeanDefinitionParser { - - /** - * Parses the {@code } tag. - */ - public FeatureSpecification doParse(Element element, ParserContext parserContext) { - MvcInterceptors mvcInterceptors = new MvcInterceptors(); +class InterceptorsBeanDefinitionParser implements BeanDefinitionParser { + public BeanDefinition parse(Element element, ParserContext parserContext) { + CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element)); + parserContext.pushContainingComponent(compDefinition); + List interceptors = DomUtils.getChildElementsByTagName(element, new String[] { "bean", "interceptor" }); for (Element interceptor : interceptors) { + RootBeanDefinition mappedInterceptorDef = new RootBeanDefinition(MappedInterceptor.class); + mappedInterceptorDef.setSource(parserContext.extractSource(interceptor)); + mappedInterceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + String[] pathPatterns; + BeanDefinitionHolder interceptorDef; if ("interceptor".equals(interceptor.getLocalName())) { List paths = DomUtils.getChildElementsByTagName(interceptor, "mapping"); - String[] pathPatterns = new String[paths.size()]; + pathPatterns = new String[paths.size()]; for (int i = 0; i < paths.size(); i++) { pathPatterns[i] = paths.get(i).getAttribute("path"); } - Element beanElement = DomUtils.getChildElementByTagName(interceptor, "bean"); - mvcInterceptors.interceptor(pathPatterns, parseBeanElement(parserContext, beanElement)); + Element interceptorBean = DomUtils.getChildElementByTagName(interceptor, "bean"); + interceptorDef = parserContext.getDelegate().parseBeanDefinitionElement(interceptorBean); + interceptorDef = parserContext.getDelegate().decorateBeanDefinitionIfRequired(interceptorBean, interceptorDef); } else { - mvcInterceptors.interceptor(null, parseBeanElement(parserContext, interceptor)); + pathPatterns = null; + interceptorDef = parserContext.getDelegate().parseBeanDefinitionElement(interceptor); + interceptorDef = parserContext.getDelegate().decorateBeanDefinitionIfRequired(interceptor, interceptorDef); } + mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, pathPatterns); + mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(1, interceptorDef); + String mappedInterceptorName = parserContext.getReaderContext().registerWithGeneratedName(mappedInterceptorDef); + parserContext.registerComponent(new BeanComponentDefinition(mappedInterceptorDef, mappedInterceptorName)); } - - return mvcInterceptors; + + parserContext.popAndRegisterContainingComponent(); + return null; } - - private BeanDefinitionHolder parseBeanElement(ParserContext parserContext, Element interceptor) { - BeanDefinitionHolder beanDef = parserContext.getDelegate().parseBeanDefinitionElement(interceptor); - beanDef = parserContext.getDelegate().decorateBeanDefinitionIfRequired(interceptor, beanDef); - return beanDef; - } - + } diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcAnnotationDriven.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcAnnotationDriven.java deleted file mode 100644 index 641327df1ec..00000000000 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcAnnotationDriven.java +++ /dev/null @@ -1,259 +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.web.servlet.config; - -import org.springframework.beans.factory.config.BeanDefinitionHolder; -import org.springframework.beans.factory.parsing.ProblemCollector; -import org.springframework.beans.factory.support.ManagedList; -import org.springframework.context.config.AbstractFeatureSpecification; -import org.springframework.context.config.FeatureSpecificationExecutor; -import org.springframework.core.convert.ConversionService; -import org.springframework.format.support.FormattingConversionServiceFactoryBean; -import org.springframework.http.converter.HttpMessageConverter; -import org.springframework.http.converter.feed.AtomFeedHttpMessageConverter; -import org.springframework.http.converter.feed.RssChannelHttpMessageConverter; -import org.springframework.http.converter.json.MappingJacksonHttpMessageConverter; -import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter; -import org.springframework.validation.MessageCodesResolver; -import org.springframework.validation.Validator; -import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; -import org.springframework.web.bind.support.WebArgumentResolver; -import org.springframework.web.method.support.HandlerMethodArgumentResolver; -import org.springframework.web.servlet.mvc.method.annotation.support.ServletWebArgumentResolverAdapter; - -/** - * Specifies the Spring MVC "annotation-driven" container feature. The - * feature provides the following fine-grained configuration: - * - *
    - *
  • {@code DefaultAnnotationHandlerMapping} bean for mapping HTTP Servlet Requests - * to {@code @Controller} methods using {@code @RequestMapping} annotations. - *
  • {@code AnnotationMethodHandlerAdapter} bean for invoking annotated - * {@code @Controller} methods. - *
  • {@code HandlerExceptionResolver} beans for invoking {@code @ExceptionHandler} - * controller methods and for mapping Spring exception to HTTP status codes. - *
- * - *

The {@code HandlerAdapter} is further configured with the following, which apply - * globally (across controllers invoked though the {@code AnnotationMethodHandlerAdapter}): - * - *

    - *
  • {@link ConversionService} - a custom instance can be provided via - * {@link #conversionService(ConversionService)}. Otherwise it defaults to a fresh - * {@link ConversionService} instance created by the default - * {@link FormattingConversionServiceFactoryBean}. - *
  • {@link Validator} - a custom instance can be provided via - * {@link #validator(Validator)}. Otherwise it defaults to a fresh {@code Validator} - * instance created by the default {@link LocalValidatorFactoryBean} assuming - * JSR-303 API is present on the classpath. - *
  • {@code HttpMessageConverter} beans including the {@link - * Jaxb2RootElementHttpMessageConverter} assuming JAXB2 is present on the - * classpath, the {@link MappingJacksonHttpMessageConverter} assuming Jackson - * is present on the classpath, and the {@link AtomFeedHttpMessageConverter} and the - * {@link RssChannelHttpMessageConverter} converters assuming Rome is present on - * the classpath. - *
  • Optionally, custom {@code WebArgumentResolver} beans to use for resolving - * custom arguments to handler methods. These are typically implemented to detect - * special parameter types, resolving well-known argument values for them. - *
- * - * @author Rossen Stoyanchev - * @since 3.1 - */ -public final class MvcAnnotationDriven extends AbstractFeatureSpecification { - - private static final Class EXECUTOR_TYPE = MvcAnnotationDrivenExecutor.class; - - private Object conversionService; - - private Object validator; - - private Object messageCodesResolver; - - private boolean shouldRegisterDefaultMessageConverters = true; - - private ManagedList messageConverters = new ManagedList(); - - private ManagedList argumentResolvers = new ManagedList(); - - /** - * Creates an MvcAnnotationDriven specification. - */ - public MvcAnnotationDriven() { - super(EXECUTOR_TYPE); - } - - /** - *

The ConversionService bean instance to use for type conversion during - * field binding. This is not required input. It only needs to be provided - * explicitly if custom converters or formatters need to be configured. - * - *

If not provided, a default FormattingConversionService is registered - * that contains converters to/from standard JDK types. In addition, full - * support for date/time formatting will be installed if the Joda Time - * library is present on the classpath. - * - * @param conversionService the ConversionService instance to use - */ - public MvcAnnotationDriven conversionService(ConversionService conversionService) { - this.conversionService = conversionService; - return this; - } - - /** - *

The ConversionService to use for type conversion during field binding. - * This is an alternative to {@link #conversionService(ConversionService)} - * allowing you to provide a bean name rather than a bean instance. - * - * @param conversionService the ConversionService bean name - */ - public MvcAnnotationDriven conversionService(String conversionService) { - this.conversionService = conversionService; - return this; - } - - Object conversionService() { - return this.conversionService; - } - - /** - * The HttpMessageConverter types to use for converting @RequestBody method - * parameters and @ResponseBody method return values. HttpMessageConverter - * registrations provided here will take precedence over HttpMessageConverter - * types registered by default. - * Also see {@link #shouldRegisterDefaultMessageConverters(boolean)} if - * default registrations are to be turned off altogether. - * - * @param converters the message converters - */ - public MvcAnnotationDriven messageConverters(HttpMessageConverter... converters) { - for (HttpMessageConverter converter : converters) { - this.messageConverters.add(converter); - } - return this; - } - - void messageConverters(ManagedList converterBeanDefinitions) { - this.messageConverters.addAll(converterBeanDefinitions); - } - - ManagedList messageConverters() { - return this.messageConverters; - } - - /** - * Indicates whether or not default HttpMessageConverter registrations should - * be added in addition to the ones provided via - * {@link #messageConverters(HttpMessageConverter...)} - * - * @param shouldRegister true will result in registration of defaults. - */ - public MvcAnnotationDriven shouldRegisterDefaultMessageConverters(boolean shouldRegister) { - this.shouldRegisterDefaultMessageConverters = shouldRegister; - return this; - } - - boolean shouldRegisterDefaultMessageConverters() { - return this.shouldRegisterDefaultMessageConverters; - } - - public MvcAnnotationDriven argumentResolvers(HandlerMethodArgumentResolver... resolvers) { - for (HandlerMethodArgumentResolver resolver : resolvers) { - this.argumentResolvers.add(resolver); - } - return this; - } - - public MvcAnnotationDriven argumentResolvers(WebArgumentResolver... resolvers) { - for (WebArgumentResolver resolver : resolvers) { - this.argumentResolvers.add(new ServletWebArgumentResolverAdapter(resolver)); - } - return this; - } - - void argumentResolvers(ManagedList resolverBeanDefinitions) { - this.argumentResolvers.addAll(resolverBeanDefinitions); - } - - ManagedList argumentResolvers() { - return this.argumentResolvers; - } - - /** - * The Validator bean instance to use to validate Controller model objects. - * This is not required input. It only needs to be specified explicitly if - * a custom Validator needs to be configured. - * - *

If not specified, JSR-303 validation will be installed if a JSR-303 - * provider is present on the classpath. - * - * @param validator the Validator bean instance - */ - public MvcAnnotationDriven validator(Validator validator) { - this.validator = validator; - return this; - } - - /** - * The Validator bean instance to use to validate Controller model objects. - * This is an alternative to {@link #validator(Validator)} allowing you to - * provide a bean name rather than a bean instance. - * - * @param validator the Validator bean name - */ - public MvcAnnotationDriven validator(String validator) { - this.validator = validator; - return this; - } - - Object validator() { - return this.validator; - } - - /** - * The MessageCodesResolver to use to build message codes from data binding - * and validation error codes. This is not required input. If not specified - * the DefaultMessageCodesResolver is used. - * - * @param messageCodesResolver the MessageCodesResolver bean instance - */ - public MvcAnnotationDriven messageCodesResolver(MessageCodesResolver messageCodesResolver) { - this.messageCodesResolver = messageCodesResolver; - return this; - } - - /** - * The MessageCodesResolver to use to build message codes from data binding - * and validation error codes. This is an alternative to - * {@link #messageCodesResolver(MessageCodesResolver)} allowing you to provide - * a bean name rather than a bean instance. - * - * @param messageCodesResolver the MessageCodesResolver bean name - */ - public MvcAnnotationDriven messageCodesResolver(String messageCodesResolver) { - this.messageCodesResolver = messageCodesResolver; - return this; - } - - Object messageCodesResolver() { - return this.messageCodesResolver; - } - - @Override - protected void doValidate(ProblemCollector problems) { - } - -} diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcAnnotationDrivenExecutor.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcAnnotationDrivenExecutor.java deleted file mode 100644 index 1337ec4660f..00000000000 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcAnnotationDrivenExecutor.java +++ /dev/null @@ -1,236 +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.web.servlet.config; - -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.config.RuntimeBeanReference; -import org.springframework.beans.factory.parsing.BeanComponentDefinition; -import org.springframework.beans.factory.parsing.ComponentRegistrar; -import org.springframework.beans.factory.parsing.CompositeComponentDefinition; -import org.springframework.beans.factory.support.ManagedList; -import org.springframework.beans.factory.support.RootBeanDefinition; -import org.springframework.context.config.AbstractSpecificationExecutor; -import org.springframework.context.config.SpecificationContext; -import org.springframework.format.support.FormattingConversionServiceFactoryBean; -import org.springframework.http.converter.ByteArrayHttpMessageConverter; -import org.springframework.http.converter.HttpMessageConverter; -import org.springframework.http.converter.ResourceHttpMessageConverter; -import org.springframework.http.converter.StringHttpMessageConverter; -import org.springframework.http.converter.feed.AtomFeedHttpMessageConverter; -import org.springframework.http.converter.feed.RssChannelHttpMessageConverter; -import org.springframework.http.converter.json.MappingJacksonHttpMessageConverter; -import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter; -import org.springframework.http.converter.xml.SourceHttpMessageConverter; -import org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter; -import org.springframework.util.ClassUtils; -import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; -import org.springframework.web.bind.support.ConfigurableWebBindingInitializer; -import org.springframework.web.servlet.handler.ConversionServiceExposingInterceptor; -import org.springframework.web.servlet.handler.MappedInterceptor; -import org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver; -import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMethodAdapter; -import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver; -import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMethodMapping; -import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver; - -/** - * Executes {@link MvcAnnotationDriven} specifications, creating and registering - * bean definitions as appropriate based on the configuration within. - * - * @author Keith Donald - * @author Juergen Hoeller - * @author Arjen Poutsma - * @author Rossen Stoyanchev - * @since 3.1 - * @see MvcAnnotationDriven - */ -final class MvcAnnotationDrivenExecutor extends AbstractSpecificationExecutor { - - private static final boolean jsr303Present = ClassUtils.isPresent("javax.validation.Validator", - AnnotationDrivenBeanDefinitionParser.class.getClassLoader()); - - private static final boolean jaxb2Present = ClassUtils.isPresent("javax.xml.bind.Binder", - AnnotationDrivenBeanDefinitionParser.class.getClassLoader()); - - private static final boolean jacksonPresent = ClassUtils.isPresent("org.codehaus.jackson.map.ObjectMapper", - AnnotationDrivenBeanDefinitionParser.class.getClassLoader()) - && ClassUtils.isPresent("org.codehaus.jackson.JsonGenerator", - AnnotationDrivenBeanDefinitionParser.class.getClassLoader()); - - private static boolean romePresent = ClassUtils.isPresent("com.sun.syndication.feed.WireFeed", - AnnotationDrivenBeanDefinitionParser.class.getClassLoader()); - - @Override - public void doExecute(MvcAnnotationDriven spec, SpecificationContext specContext) { - ComponentRegistrar registrar = specContext.getRegistrar(); - Object source = spec.source(); - - RootBeanDefinition methodMappingDef = new RootBeanDefinition(RequestMappingHandlerMethodMapping.class); - methodMappingDef.setSource(source); - methodMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - methodMappingDef.getPropertyValues().add("order", 0); - String methodMappingName = registrar.registerWithGeneratedName(methodMappingDef); - - Object conversionService = getConversionService(spec, registrar); - Object validator = getValidator(spec, registrar); - Object messageCodesResolver = getMessageCodesResolver(spec, registrar); - - RootBeanDefinition bindingDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class); - bindingDef.setSource(source); - bindingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - bindingDef.getPropertyValues().add("conversionService", conversionService); - bindingDef.getPropertyValues().add("validator", validator); - bindingDef.getPropertyValues().add("messageCodesResolver", messageCodesResolver); - - ManagedList messageConverters = getMessageConverters(spec, registrar); - - RootBeanDefinition methodAdapterDef = new RootBeanDefinition(RequestMappingHandlerMethodAdapter.class); - methodAdapterDef.setSource(source); - methodAdapterDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - methodAdapterDef.getPropertyValues().add("webBindingInitializer", bindingDef); - methodAdapterDef.getPropertyValues().add("messageConverters", messageConverters); - if (!spec.argumentResolvers().isEmpty()) { - methodAdapterDef.getPropertyValues().add("customArgumentResolvers", spec.argumentResolvers()); - } - String methodAdapterName = registrar.registerWithGeneratedName(methodAdapterDef); - - RootBeanDefinition csInterceptorDef = new RootBeanDefinition(ConversionServiceExposingInterceptor.class); - csInterceptorDef.setSource(source); - csInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, conversionService); - RootBeanDefinition mappedCsInterceptorDef = new RootBeanDefinition(MappedInterceptor.class); - mappedCsInterceptorDef.setSource(source); - mappedCsInterceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - mappedCsInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, (Object) null); - mappedCsInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(1, csInterceptorDef); - String mappedInterceptorName = registrar.registerWithGeneratedName(mappedCsInterceptorDef); - - RootBeanDefinition methodExceptionResolver = new RootBeanDefinition( - ExceptionHandlerExceptionResolver.class); - methodExceptionResolver.setSource(source); - methodExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - methodExceptionResolver.getPropertyValues().add("messageConverters", messageConverters); - methodExceptionResolver.getPropertyValues().add("order", 0); - String methodExceptionResolverName = registrar.registerWithGeneratedName(methodExceptionResolver); - - RootBeanDefinition responseStatusExceptionResolver = new RootBeanDefinition( - ResponseStatusExceptionResolver.class); - responseStatusExceptionResolver.setSource(source); - responseStatusExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - responseStatusExceptionResolver.getPropertyValues().add("order", 1); - String responseStatusExceptionResolverName = registrar - .registerWithGeneratedName(responseStatusExceptionResolver); - - RootBeanDefinition defaultExceptionResolver = new RootBeanDefinition(DefaultHandlerExceptionResolver.class); - defaultExceptionResolver.setSource(source); - defaultExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - defaultExceptionResolver.getPropertyValues().add("order", 2); - String defaultExceptionResolverName = registrar.registerWithGeneratedName(defaultExceptionResolver); - - CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(spec.sourceName(), source); - compDefinition.addNestedComponent(new BeanComponentDefinition(methodMappingDef, methodMappingName)); - compDefinition.addNestedComponent(new BeanComponentDefinition(methodAdapterDef, methodAdapterName)); - compDefinition.addNestedComponent(new BeanComponentDefinition(methodExceptionResolver, methodExceptionResolverName)); - compDefinition.addNestedComponent(new BeanComponentDefinition(responseStatusExceptionResolver, - responseStatusExceptionResolverName)); - compDefinition.addNestedComponent(new BeanComponentDefinition(defaultExceptionResolver, - defaultExceptionResolverName)); - compDefinition.addNestedComponent(new BeanComponentDefinition(mappedCsInterceptorDef, mappedInterceptorName)); - registrar.registerComponent(compDefinition); - } - - private Object getConversionService(MvcAnnotationDriven spec, ComponentRegistrar registrar) { - if (spec.conversionService() != null) { - return getBeanOrReference(spec.conversionService()); - } else { - RootBeanDefinition conversionDef = new RootBeanDefinition(FormattingConversionServiceFactoryBean.class); - conversionDef.setSource(spec.source()); - conversionDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - String conversionName = registrar.registerWithGeneratedName(conversionDef); - registrar.registerComponent(new BeanComponentDefinition(conversionDef, conversionName)); - return new RuntimeBeanReference(conversionName); - } - } - - private Object getValidator(MvcAnnotationDriven spec, ComponentRegistrar registrar) { - if (spec.validator() != null) { - return getBeanOrReference(spec.validator()); - } else if (jsr303Present) { - RootBeanDefinition validatorDef = new RootBeanDefinition(LocalValidatorFactoryBean.class); - validatorDef.setSource(spec.source()); - validatorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - String validatorName = registrar.registerWithGeneratedName(validatorDef); - registrar.registerComponent(new BeanComponentDefinition(validatorDef, validatorName)); - return new RuntimeBeanReference(validatorName); - } else { - return null; - } - } - - private Object getMessageCodesResolver(MvcAnnotationDriven spec, ComponentRegistrar registrar) { - if (spec.messageCodesResolver() != null) { - return getBeanOrReference(spec.messageCodesResolver()); - } else { - return null; - } - } - - private ManagedList getMessageConverters(MvcAnnotationDriven spec, ComponentRegistrar registrar) { - ManagedList messageConverters = new ManagedList(); - Object source = spec.source(); - messageConverters.setSource(source); - messageConverters.addAll(spec.messageConverters()); - if (spec.shouldRegisterDefaultMessageConverters()) { - messageConverters.add(createConverterBeanDefinition(ByteArrayHttpMessageConverter.class, source)); - RootBeanDefinition stringConverterDef = createConverterBeanDefinition(StringHttpMessageConverter.class, - source); - stringConverterDef.getPropertyValues().add("writeAcceptCharset", false); - messageConverters.add(stringConverterDef); - messageConverters.add(createConverterBeanDefinition(ResourceHttpMessageConverter.class, source)); - messageConverters.add(createConverterBeanDefinition(SourceHttpMessageConverter.class, source)); - messageConverters.add(createConverterBeanDefinition(XmlAwareFormHttpMessageConverter.class, source)); - if (jaxb2Present) { - messageConverters - .add(createConverterBeanDefinition(Jaxb2RootElementHttpMessageConverter.class, source)); - } - if (jacksonPresent) { - messageConverters.add(createConverterBeanDefinition(MappingJacksonHttpMessageConverter.class, source)); - } - if (romePresent) { - messageConverters.add(createConverterBeanDefinition(AtomFeedHttpMessageConverter.class, source)); - messageConverters.add(createConverterBeanDefinition(RssChannelHttpMessageConverter.class, source)); - } - } - return messageConverters; - } - - @SuppressWarnings("rawtypes") - private RootBeanDefinition createConverterBeanDefinition(Class converterClass, - Object source) { - RootBeanDefinition beanDefinition = new RootBeanDefinition(converterClass); - beanDefinition.setSource(source); - beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - return beanDefinition; - } - - private Object getBeanOrReference(Object bean) { - if (bean != null && bean instanceof String) { - return new RuntimeBeanReference((String) bean); - } else { - return bean; - } - } - -} diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcDefaultServletHandler.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcDefaultServletHandler.java deleted file mode 100644 index fcccac2f04f..00000000000 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcDefaultServletHandler.java +++ /dev/null @@ -1,91 +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.web.servlet.config; - -import org.springframework.beans.factory.parsing.ProblemCollector; -import org.springframework.context.config.AbstractFeatureSpecification; -import org.springframework.context.config.FeatureSpecificationExecutor; -import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; -import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter; -import org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler; - -/** - * Specifies the Spring MVC "default-servlet-handler" container feature. The - * feature provides the following fine-grained configuration: - * - *
    - *
  • {@link DefaultServletHttpRequestHandler} for serving static files by - * forwarding to the Servlet container's "default" Servlet. - *
  • {@link SimpleUrlHandlerMapping} to map the above request handler to "/**" - *
  • {@link HttpRequestHandlerAdapter} to enable the DispatcherServlet to be - * able to invoke the above request handler. - *
- * - * This handler will forward all requests to the default Servlet. Therefore - * it is important that it remains last in the order of all other URL - * HandlerMappings. That will be the case if you use the {@link MvcAnnotationDriven} - * feature or alternatively if you are setting up your customized HandlerMapping - * instance be sure to set its "order" property to a value lower than that of - * the DefaultServletHttpRequestHandler, which is Integer.MAX_VALUE. - * - * @author Rossen Stoyanchev - * @since 3.1 - */ -public final class MvcDefaultServletHandler extends AbstractFeatureSpecification { - - private static final Class EXECUTOR_TYPE = MvcDefaultServletHandlerExecutor.class; - - private String defaultServletName; - - /** - *

Creates an instance of MvcDefaultServletHandler without. - * If this constructor is used the {@link DefaultServletHttpRequestHandler} - * will try to auto-detect the container's default Servlet at startup time - * using a list of known names. - * - *

If the default Servlet cannot be detected because of using an - * unknown container or because it has been manually configured, an - * alternate constructor provided here can be used to specify the - * servlet name explicitly. - */ - public MvcDefaultServletHandler() { - super(EXECUTOR_TYPE); - } - - /** - * The name of the default Servlet to forward to for static resource requests. - * The {@link DefaultServletHttpRequestHandler} will try to auto-detect the - * container's default Servlet at startup time using a list of known names. - * However if the default Servlet cannot be detected because of using an unknown - * container or because it has been manually configured, you can use this - * constructor to set the servlet name explicitly. - * - * @param defaultServletName the name of the default servlet - */ - public MvcDefaultServletHandler(String defaultServletName) { - this(); - this.defaultServletName = defaultServletName; - } - - String defaultServletName() { - return this.defaultServletName; - } - - @Override - protected void doValidate(ProblemCollector problems) { - } - -} diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcDefaultServletHandlerExecutor.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcDefaultServletHandlerExecutor.java deleted file mode 100644 index aa57d5abb49..00000000000 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcDefaultServletHandlerExecutor.java +++ /dev/null @@ -1,82 +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.web.servlet.config; - -import java.util.Map; - -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.parsing.BeanComponentDefinition; -import org.springframework.beans.factory.parsing.ComponentRegistrar; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.beans.factory.support.ManagedMap; -import org.springframework.beans.factory.support.RootBeanDefinition; -import org.springframework.context.config.AbstractSpecificationExecutor; -import org.springframework.context.config.SpecificationContext; -import org.springframework.util.StringUtils; -import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; -import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter; -import org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler; - -/** - * Executes {@link MvcDefaultServletHandler} specifications, creating and - * registering bean definitions as appropriate based on the configuration - * within. - * - * @author Jeremy Grelle - * @author Rossen Stoyanchev - * @since 3.1 - */ -final class MvcDefaultServletHandlerExecutor extends AbstractSpecificationExecutor { - - private static final String HANDLER_ADAPTER_BEAN_NAME = "org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"; - - @Override - protected void doExecute(MvcDefaultServletHandler spec, SpecificationContext specContext) { - BeanDefinitionRegistry registry = specContext.getRegistry(); - ComponentRegistrar registrar = specContext.getRegistrar(); - Object source = spec.source(); - - if (!registry.containsBeanDefinition(HANDLER_ADAPTER_BEAN_NAME)) { - RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(HttpRequestHandlerAdapter.class); - handlerAdapterDef.setSource(source); - handlerAdapterDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - registry.registerBeanDefinition(HANDLER_ADAPTER_BEAN_NAME, handlerAdapterDef); - registrar.registerComponent(new BeanComponentDefinition(handlerAdapterDef, HANDLER_ADAPTER_BEAN_NAME)); - } - - RootBeanDefinition defaultServletHandlerDef = new RootBeanDefinition(DefaultServletHttpRequestHandler.class); - defaultServletHandlerDef.setSource(source); - defaultServletHandlerDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - if (StringUtils.hasText(spec.defaultServletName())) { - defaultServletHandlerDef.getPropertyValues().add("defaultServletName", spec.defaultServletName()); - } - String defaultServletHandlerName = registrar.registerWithGeneratedName(defaultServletHandlerDef); - registry.registerBeanDefinition(defaultServletHandlerName, defaultServletHandlerDef); - registrar.registerComponent(new BeanComponentDefinition(defaultServletHandlerDef, defaultServletHandlerName)); - - Map urlMap = new ManagedMap(); - urlMap.put("/**", defaultServletHandlerName); - RootBeanDefinition handlerMappingDef = new RootBeanDefinition(SimpleUrlHandlerMapping.class); - handlerMappingDef.setSource(source); - handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - handlerMappingDef.getPropertyValues().add("urlMap", urlMap); - String handlerMappingBeanName = registrar.registerWithGeneratedName(handlerMappingDef); - registry.registerBeanDefinition(handlerMappingBeanName, handlerMappingDef); - registrar.registerComponent(new BeanComponentDefinition(handlerMappingDef, handlerMappingBeanName)); - } - -} diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcInterceptors.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcInterceptors.java deleted file mode 100644 index 8169fdcfd08..00000000000 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcInterceptors.java +++ /dev/null @@ -1,158 +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.web.servlet.config; - -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.Map; - -import org.springframework.beans.factory.config.BeanDefinitionHolder; -import org.springframework.beans.factory.parsing.ProblemCollector; -import org.springframework.context.config.AbstractFeatureSpecification; -import org.springframework.context.config.FeatureSpecificationExecutor; -import org.springframework.util.StringUtils; -import org.springframework.web.context.request.WebRequestInterceptor; -import org.springframework.web.servlet.HandlerInterceptor; -import org.springframework.web.servlet.handler.MappedInterceptor; - -/** - * Specifies the Spring MVC "interceptors" container feature. The feature - * registers one or more {@link MappedInterceptor} bean definitions. A - * MappedInterceptor encapsulates an interceptor and one or more (optional) - * path patterns to which the interceptor is mapped. The interceptor can be - * of type {@link HandlerInterceptor} or {@link WebRequestInterceptor}. - * An interceptor can also be provided without path patterns in which case - * it applies globally to all handler invocations. - * - * @author Rossen Stoyanchev - * @since 3.1 - */ -public class MvcInterceptors extends AbstractFeatureSpecification { - - private static final Class EXECUTOR_TYPE = MvcInterceptorsExecutor.class; - - private Map interceptorMappings = new LinkedHashMap(); - - /** - * Creates an MvcInterceptors instance. - */ - public MvcInterceptors() { - super(EXECUTOR_TYPE); - } - - /** - * Add one or more {@link HandlerInterceptor HandlerInterceptors} that should - * intercept all handler invocations. - * - * @param interceptors one or more interceptors - */ - public MvcInterceptors globalInterceptors(HandlerInterceptor... interceptors) { - addInterceptorMappings(null, interceptors); - return this; - } - - /** - * Add one or more {@link WebRequestInterceptor WebRequestInterceptors} that should - * intercept all handler invocations. - * - * @param interceptors one or more interceptors - */ - public MvcInterceptors globalInterceptors(WebRequestInterceptor... interceptors) { - addInterceptorMappings(null, interceptors); - return this; - } - - /** - * Add one or more interceptors by bean name that should intercept all handler - * invocations. - * - * @param interceptors interceptor bean names - */ - public MvcInterceptors globalInterceptors(String... interceptors) { - addInterceptorMappings(null, interceptors); - return this; - } - - /** - * Add one or more {@link HandlerInterceptor HandlerInterceptors} and map - * them to the specified path patterns. - * - * @param pathPatterns the pathPatterns to map the interceptor to - * @param interceptors the interceptors - */ - public MvcInterceptors mappedInterceptors(String[] pathPatterns, HandlerInterceptor... interceptors) { - addInterceptorMappings(pathPatterns, interceptors); - return this; - } - - /** - * Add one or more {@link WebRequestInterceptor WebRequestInterceptors} and - * map them to the specified path patterns. - * - * @param pathPatterns the pathPatterns to map the interceptor to - * @param interceptors the interceptors - */ - public MvcInterceptors mappedInterceptors(String[] pathPatterns, WebRequestInterceptor... interceptors) { - addInterceptorMappings(pathPatterns, interceptors); - return this; - } - - /** - * Add one or more interceptors by bean name and map them to the specified - * path patterns. - * - * @param pathPatterns the pathPatterns to map to - * @param interceptors the interceptors - */ - public MvcInterceptors mappedInterceptors(String[] pathPatterns, String... interceptors) { - addInterceptorMappings(pathPatterns, interceptors); - return this; - } - - void interceptor(String[] pathPatterns, BeanDefinitionHolder interceptor) { - addInterceptorMappings(pathPatterns, new Object[] { interceptor }); - } - - Map interceptorMappings() { - return Collections.unmodifiableMap(interceptorMappings); - } - - private void addInterceptorMappings(String[] pathPatterns, Object[] interceptors) { - for (Object interceptor : interceptors) { - interceptorMappings.put(interceptor, pathPatterns); - } - } - - @Override - protected void doValidate(ProblemCollector problems) { - if (interceptorMappings.size() == 0) { - problems.error("No interceptors defined."); - } - for (Object interceptor : interceptorMappings.keySet()) { - if (interceptor == null) { - problems.error("Null interceptor provided."); - } - if (interceptorMappings.get(interceptor) != null) { - for (String pattern : interceptorMappings.get(interceptor)) { - if (!StringUtils.hasText(pattern)) { - problems.error("Empty path pattern specified for " + interceptor); - } - } - } - } - } - -} diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcInterceptorsExecutor.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcInterceptorsExecutor.java deleted file mode 100644 index 029caaf24f7..00000000000 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcInterceptorsExecutor.java +++ /dev/null @@ -1,60 +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.web.servlet.config; - -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.parsing.BeanComponentDefinition; -import org.springframework.beans.factory.parsing.ComponentRegistrar; -import org.springframework.beans.factory.parsing.CompositeComponentDefinition; -import org.springframework.beans.factory.support.RootBeanDefinition; -import org.springframework.context.config.AbstractSpecificationExecutor; -import org.springframework.context.config.SpecificationContext; -import org.springframework.web.servlet.handler.MappedInterceptor; - -/** - * Executes {@link MvcInterceptors} specification, creating and registering - * bean definitions as appropriate based on the configuration within. - * - * @author Keith Donald - * @author Rossen Stoyanchev - * - * @since 3.1 - */ -final class MvcInterceptorsExecutor extends AbstractSpecificationExecutor { - - @Override - protected void doExecute(MvcInterceptors spec, SpecificationContext specContext) { - ComponentRegistrar registrar = specContext.getRegistrar(); - Object source = spec.source(); - - CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(spec.sourceName(), source); - - for (Object interceptor : spec.interceptorMappings().keySet()) { - RootBeanDefinition beanDef = new RootBeanDefinition(MappedInterceptor.class); - beanDef.setSource(source); - beanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - beanDef.getConstructorArgumentValues().addIndexedArgumentValue(0, - spec.interceptorMappings().get(interceptor)); - beanDef.getConstructorArgumentValues().addIndexedArgumentValue(1, interceptor); - - String beanName = registrar.registerWithGeneratedName(beanDef); - compDefinition.addNestedComponent(new BeanComponentDefinition(beanDef, beanName)); - } - - registrar.registerComponent(compDefinition); - } - -} diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcResources.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcResources.java deleted file mode 100644 index e85d12dbac1..00000000000 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcResources.java +++ /dev/null @@ -1,179 +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.web.servlet.config; - -import org.springframework.beans.factory.parsing.ProblemCollector; -import org.springframework.context.config.AbstractFeatureSpecification; -import org.springframework.context.config.FeatureSpecificationExecutor; -import org.springframework.core.Ordered; -import org.springframework.core.io.Resource; -import org.springframework.util.StringUtils; -import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; -import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter; -import org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping; -import org.springframework.web.servlet.resource.ResourceHttpRequestHandler; - -/** - * Specifies the Spring MVC "resources" container feature. The - * feature provides the following fine-grained configuration: - * - *

    - *
  • {@link ResourceHttpRequestHandler} to serve static resources from a - * list of web-root relative, classpath, or other locations. - *
  • {@link SimpleUrlHandlerMapping} to map the above request handler to a - * a specific path pattern (e.g. "/resources/**"). - *
  • {@link HttpRequestHandlerAdapter} to enable the DispatcherServlet to be - * able to invoke the above request handler. - *
- * - * @author Rossen Stoynchev - * @since 3.1 - */ -public final class MvcResources extends AbstractFeatureSpecification { - - private static final Class EXECUTOR_TYPE = MvcResourcesExecutor.class; - - private Object[] locations; - - private String mapping; - - private Object cachePeriod; - - private Object order = Ordered.LOWEST_PRECEDENCE - 1; - - /** - * Create an MvcResources specification instance. See alternate constructor - * you prefer to use {@link Resource} instances instead of {@code String}-based - * resource locations. - * - * @param mapping - the URL path pattern within the current Servlet context to - * use to identify resource requests (e.g. "/resources/**"). - * @param locations - locations of resources containing static content to be - * served. Each location must point to a valid directory. Locations will be - * checked in the order specified. For example if "/" and - * "classpath:/META-INF/public-web-resources/" are configured resources will - * be served from the Web root and from any JAR on the classpath that contains - * a /META-INF/public-web-resources/ directory, with resources under the Web root - * taking precedence. - */ - public MvcResources(String mapping, String... locations) { - super(EXECUTOR_TYPE); - this.locations = locations; - this.mapping = mapping; - } - - /** - * Create an MvcResources specification instance. See alternate constructor - * defined here if you prefer to use String-based path patterns. - * - * @param mapping - the URL path pattern within the current Servlet context to - * use to identify resource requests (e.g. "/resources/**"). - * @param resources - Spring {@link Resource} objects containing static - * content to be served. Resources will be checked in the order specified. - */ - public MvcResources(String mapping, Resource... resources) { - super(EXECUTOR_TYPE); - this.locations = resources; - this.mapping = mapping; - } - - /** - * The period of time resources should be cached for in seconds. - * The default is to not send any cache headers but rather to rely on - * last-modified timestamps only. - *

Set this to 0 in order to send cache headers that prevent caching, - * or to a positive number of seconds in order to send cache headers - * with the given max-age value. - * - * @param cachePeriod the cache period in seconds - */ - public MvcResources cachePeriod(Integer cachePeriod) { - this.cachePeriod = cachePeriod; - return this; - } - - /** - * Specify a cachePeriod as a String. An alternative to {@link #cachePeriod(Integer)}. - * The String must represent an Integer after placeholder and SpEL expression - * resolution. - * - * @param cachePeriod the cache period in seconds - */ - public MvcResources cachePeriod(String cachePeriod) { - this.cachePeriod = cachePeriod; - return this; - } - - /** - * Specify a cachePeriod as a String. An alternative to {@link #cachePeriod(Integer)}. - * The String must represent an Integer after placeholder and SpEL expression - * resolution. - *

Sets the order for the SimpleUrlHandlerMapping used to match resource - * requests relative to order value for other HandlerMapping instances - * such as the {@link DefaultAnnotationHandlerMapping} used to match - * controller requests. - * - * @param order the order to use. The default value is - * {@link Ordered#LOWEST_PRECEDENCE} - 1. - */ - public MvcResources order(Integer order) { - this.order = order; - return this; - } - - /** - * Specify an order as a String. An alternative to {@link #order(Integer)}. - * The String must represent an Integer after placeholder and SpEL expression - * resolution. - * - * @param order the order to use. The default value is - * {@link Ordered#LOWEST_PRECEDENCE} - 1. - */ - public MvcResources order(String order) { - this.order = order; - return this; - } - - // Package private accessors - - Object cachePeriod() { - return cachePeriod; - } - - Object[] locations() { - return this.locations; - } - - String mapping() { - return mapping; - } - - Object order() { - return order; - } - - @Override - protected void doValidate(ProblemCollector problems) { - if (!StringUtils.hasText(mapping)) { - problems.error("Mapping is required"); - } - if (locations == null || locations.length == 0) { - problems.error("At least one location is required"); - } - } - -} diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcResourcesExecutor.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcResourcesExecutor.java deleted file mode 100644 index a61db228745..00000000000 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcResourcesExecutor.java +++ /dev/null @@ -1,85 +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.web.servlet.config; - -import java.util.Map; - -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.parsing.BeanComponentDefinition; -import org.springframework.beans.factory.parsing.ComponentRegistrar; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.beans.factory.support.ManagedMap; -import org.springframework.beans.factory.support.RootBeanDefinition; -import org.springframework.context.config.AbstractSpecificationExecutor; -import org.springframework.context.config.SpecificationContext; -import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; -import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter; -import org.springframework.web.servlet.resource.ResourceHttpRequestHandler; - -/** - * Executes {@link MvcResources} specifications, creating and registering - * bean definitions as appropriate based on the configuration within. - * - * @author Keith Donald - * @author Jeremy Grelle - * @author Rossen Stoyanchev - * @since 3.1 - */ -final class MvcResourcesExecutor extends AbstractSpecificationExecutor { - - private static final String HANDLER_ADAPTER_BEAN_NAME = "org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"; - - @Override - protected void doExecute(MvcResources spec, SpecificationContext specContext) { - BeanDefinitionRegistry registry = specContext.getRegistry(); - ComponentRegistrar registrar = specContext.getRegistrar(); - Object source = spec.source(); - - if (!registry.containsBeanDefinition(HANDLER_ADAPTER_BEAN_NAME)) { - RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(HttpRequestHandlerAdapter.class); - handlerAdapterDef.setSource(source); - handlerAdapterDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - registry.registerBeanDefinition(HANDLER_ADAPTER_BEAN_NAME, handlerAdapterDef); - registrar.registerComponent(new BeanComponentDefinition(handlerAdapterDef, HANDLER_ADAPTER_BEAN_NAME)); - } - - RootBeanDefinition resourceHandlerDef = new RootBeanDefinition(ResourceHttpRequestHandler.class); - resourceHandlerDef.setSource(source); - resourceHandlerDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - resourceHandlerDef.getPropertyValues().add("locations", spec.locations()); - if (spec.cachePeriod() != null) { - resourceHandlerDef.getPropertyValues().add("cacheSeconds", spec.cachePeriod()); - } - String resourceHandlerBeanName = registrar.registerWithGeneratedName(resourceHandlerDef); - registry.registerBeanDefinition(resourceHandlerBeanName, resourceHandlerDef); - registrar.registerComponent(new BeanComponentDefinition(resourceHandlerDef, resourceHandlerBeanName)); - - Map urlMap = new ManagedMap(); - urlMap.put(spec.mapping(), resourceHandlerBeanName); - RootBeanDefinition handlerMappingDef = new RootBeanDefinition(SimpleUrlHandlerMapping.class); - handlerMappingDef.setSource(source); - handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - handlerMappingDef.getPropertyValues().add("urlMap", urlMap); - if (spec.order() != null) { - handlerMappingDef.getPropertyValues().add("order", spec.order()); - } - String beanName = registrar.registerWithGeneratedName(handlerMappingDef); - registry.registerBeanDefinition(beanName, handlerMappingDef); - registrar.registerComponent(new BeanComponentDefinition(handlerMappingDef, beanName)); - } - -} diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcViewControllers.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcViewControllers.java deleted file mode 100644 index 6b13652e411..00000000000 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcViewControllers.java +++ /dev/null @@ -1,90 +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.web.servlet.config; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import org.springframework.beans.factory.parsing.ProblemCollector; -import org.springframework.context.config.AbstractFeatureSpecification; -import org.springframework.context.config.FeatureSpecificationExecutor; -import org.springframework.util.StringUtils; -import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; -import org.springframework.web.servlet.mvc.ParameterizableViewController; -import org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter; - -/** - * Specifies the Spring MVC "View Controllers" container feature. The - * feature allows specifying one or more path to view name mappings. - * It sets up the following fine-grained configuration: - * - *

    - *
  • {@link ParameterizableViewController} for each path/view name pair. - *
  • {@link SimpleUrlHandlerMapping} mapping each view controller to its path. - *
  • {@link SimpleControllerHandlerAdapter} to enable the DispatcherServlet - * to invoke the view controllers. - *
- * - * @author Rossen Stoyanchev - * @author Chris Beams - * @since 3.1 - */ -public final class MvcViewControllers extends AbstractFeatureSpecification { - - private static final Class EXECUTOR_TYPE = MvcViewControllersExecutor.class; - - private Map mappings = new HashMap(); - - public MvcViewControllers(String path) { - this(path, null); - } - - public MvcViewControllers(String path, String viewName) { - super(EXECUTOR_TYPE); - this.mappings.put(path, viewName); - } - - public MvcViewControllers viewController(String path) { - return this.viewController(path, null); - } - - public MvcViewControllers viewController(String path, String viewName) { - this.mappings.put(path, viewName); - return this; - } - - Map mappings() { - return Collections.unmodifiableMap(mappings); - } - - @Override - protected void doValidate(ProblemCollector problems) { - if (mappings.size() == 0) { - problems.error("At least one ViewController must be defined"); - } - for (String path : mappings.keySet()) { - if (!StringUtils.hasText(path)) { - problems.error("The path attribute in a ViewController is required"); - } - String viewName = mappings.get(path); - if (viewName != null && viewName.isEmpty()) { - problems.error("The view name in a ViewController may be null but not empty."); - } - } - } - -} diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcViewControllersExecutor.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcViewControllersExecutor.java deleted file mode 100644 index 33e82089ce0..00000000000 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcViewControllersExecutor.java +++ /dev/null @@ -1,89 +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.web.servlet.config; - -import java.util.Map; - -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.parsing.BeanComponentDefinition; -import org.springframework.beans.factory.parsing.ComponentRegistrar; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.beans.factory.support.ManagedMap; -import org.springframework.beans.factory.support.RootBeanDefinition; -import org.springframework.context.config.AbstractSpecificationExecutor; -import org.springframework.context.config.SpecificationContext; -import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; -import org.springframework.web.servlet.mvc.ParameterizableViewController; -import org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter; - -/** - * Executes {@link MvcViewControllers} specification, creating and registering - * bean definitions as appropriate based on the configuration within. - * - * @author Keith Donald - * @author Christian Dupuis - * @author Rossen Stoyanchev - * @since 3.1 - */ -final class MvcViewControllersExecutor extends AbstractSpecificationExecutor { - - private static final String HANDLER_ADAPTER_BEAN_NAME = "org.springframework.web.servlet.config.viewControllerHandlerAdapter"; - - private static final String HANDLER_MAPPING_BEAN_NAME = "org.springframework.web.servlet.config.viewControllerHandlerMapping"; - - @Override - protected void doExecute(MvcViewControllers spec, SpecificationContext specContext) { - BeanDefinitionRegistry registry = specContext.getRegistry(); - ComponentRegistrar registrar = specContext.getRegistrar(); - Object source = spec.source(); - - if (!registry.containsBeanDefinition(HANDLER_ADAPTER_BEAN_NAME)) { - RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(SimpleControllerHandlerAdapter.class); - handlerAdapterDef.setSource(source); - handlerAdapterDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - registry.registerBeanDefinition(HANDLER_ADAPTER_BEAN_NAME, handlerAdapterDef); - registrar.registerComponent(new BeanComponentDefinition(handlerAdapterDef, HANDLER_ADAPTER_BEAN_NAME)); - } - - BeanDefinition handlerMappingBeanDef = null; - if (!registry.containsBeanDefinition(HANDLER_MAPPING_BEAN_NAME)) { - RootBeanDefinition beanDef = new RootBeanDefinition(SimpleUrlHandlerMapping.class); - beanDef.setSource(source); - beanDef.getPropertyValues().add("order", "1"); - beanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - registry.registerBeanDefinition(HANDLER_MAPPING_BEAN_NAME, beanDef); - registrar.registerComponent(new BeanComponentDefinition(beanDef, HANDLER_MAPPING_BEAN_NAME)); - handlerMappingBeanDef = beanDef; - } else { - handlerMappingBeanDef = registry.getBeanDefinition(HANDLER_MAPPING_BEAN_NAME); - } - - for (Map.Entry entry : spec.mappings().entrySet()) { - RootBeanDefinition viewControllerDef = new RootBeanDefinition(ParameterizableViewController.class); - viewControllerDef.setSource(source); - if (entry.getValue() != null) { - viewControllerDef.getPropertyValues().add("viewName", entry.getValue()); - } - if (!handlerMappingBeanDef.getPropertyValues().contains("urlMap")) { - handlerMappingBeanDef.getPropertyValues().add("urlMap", new ManagedMap()); - } - @SuppressWarnings("unchecked") - Map urlMap = (Map) handlerMappingBeanDef - .getPropertyValues().getPropertyValue("urlMap").getValue(); - urlMap.put(entry.getKey(), viewControllerDef); - } - } - -} diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/ResourcesBeanDefinitionParser.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/ResourcesBeanDefinitionParser.java index 058652afcf2..03654ab9e5b 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/ResourcesBeanDefinitionParser.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/ResourcesBeanDefinitionParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2010 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,40 +16,89 @@ package org.springframework.web.servlet.config; -import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.context.config.AbstractSpecificationBeanDefinitionParser; -import org.springframework.context.config.FeatureSpecification; -import org.springframework.util.StringUtils; +import java.util.Map; + import org.w3c.dom.Element; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.parsing.BeanComponentDefinition; +import org.springframework.beans.factory.support.ManagedMap; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.beans.factory.xml.BeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.core.Ordered; +import org.springframework.util.StringUtils; +import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; +import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter; +import org.springframework.web.servlet.resource.ResourceHttpRequestHandler; + /** * {@link org.springframework.beans.factory.xml.BeanDefinitionParser} that parses a - * {@code resources} element. + * {@code resources} element to register a {@link ResourceHttpRequestHandler}. + * Will also register a {@link SimpleUrlHandlerMapping} for mapping resource requests, + * and a {@link HttpRequestHandlerAdapter} if necessary. * - * @author Rossen Stoyanchev + * @author Keith Donald + * @author Jeremy Grelle * @since 3.0.4 - * @see MvcResources - * @see MvcResourcesExecutor */ -class ResourcesBeanDefinitionParser extends AbstractSpecificationBeanDefinitionParser { +class ResourcesBeanDefinitionParser extends AbstractHttpRequestHandlerBeanDefinitionParser implements BeanDefinitionParser { - /** - * Parses the {@code } tag - */ - public FeatureSpecification doParse(Element element, ParserContext parserContext) { - String mapping = element.getAttribute("mapping"); - String[] locations = - StringUtils.commaDelimitedListToStringArray(element.getAttribute("location")); - - MvcResources spec = new MvcResources(mapping, locations); - if (element.hasAttribute("cache-period")) { - spec.cachePeriod(element.getAttribute("cache-period")); + @Override + public void doParse(Element element, ParserContext parserContext) { + Object source = parserContext.extractSource(element); + registerResourceMappings(parserContext, element, source); + } + + private void registerResourceMappings(ParserContext parserContext, Element element, Object source) { + String resourceHandlerName = registerResourceHandler(parserContext, element, source); + if (resourceHandlerName == null) { + return; } - if (element.hasAttribute("order")) { - spec.order(element.getAttribute("order")); + + Map urlMap = new ManagedMap(); + String resourceRequestPath = element.getAttribute("mapping"); + if (!StringUtils.hasText(resourceRequestPath)) { + parserContext.getReaderContext().error("The 'mapping' attribute is required.", parserContext.extractSource(element)); + return; + } + urlMap.put(resourceRequestPath, resourceHandlerName); + + RootBeanDefinition handlerMappingDef = new RootBeanDefinition(SimpleUrlHandlerMapping.class); + handlerMappingDef.setSource(source); + handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + handlerMappingDef.getPropertyValues().add("urlMap", urlMap); + + String order = element.getAttribute("order"); + // use a default of near-lowest precedence, still allowing for even lower precedence in other mappings + handlerMappingDef.getPropertyValues().add("order", StringUtils.hasText(order) ? order : Ordered.LOWEST_PRECEDENCE - 1); + + String beanName = parserContext.getReaderContext().generateBeanName(handlerMappingDef); + parserContext.getRegistry().registerBeanDefinition(beanName, handlerMappingDef); + parserContext.registerComponent(new BeanComponentDefinition(handlerMappingDef, beanName)); + } + + private String registerResourceHandler(ParserContext parserContext, Element element, Object source) { + String locationAttr = element.getAttribute("location"); + if (!StringUtils.hasText(locationAttr)) { + parserContext.getReaderContext().error("The 'location' attribute is required.", parserContext.extractSource(element)); + return null; + } + + RootBeanDefinition resourceHandlerDef = new RootBeanDefinition(ResourceHttpRequestHandler.class); + resourceHandlerDef.setSource(source); + resourceHandlerDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + resourceHandlerDef.getPropertyValues().add("locations", StringUtils.commaDelimitedListToStringArray(locationAttr)); + + String cacheSeconds = element.getAttribute("cache-period"); + if (StringUtils.hasText(cacheSeconds)) { + resourceHandlerDef.getPropertyValues().add("cacheSeconds", cacheSeconds); } - return spec; + String beanName = parserContext.getReaderContext().generateBeanName(resourceHandlerDef); + parserContext.getRegistry().registerBeanDefinition(beanName, resourceHandlerDef); + parserContext.registerComponent(new BeanComponentDefinition(resourceHandlerDef, beanName)); + return beanName; } } diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/ViewControllerBeanDefinitionParser.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/ViewControllerBeanDefinitionParser.java index 5c6f3293be7..36b985e99c3 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/ViewControllerBeanDefinitionParser.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/ViewControllerBeanDefinitionParser.java @@ -16,30 +16,88 @@ package org.springframework.web.servlet.config; -import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.context.config.AbstractSpecificationBeanDefinitionParser; -import org.springframework.context.config.FeatureSpecification; -import org.springframework.web.servlet.mvc.ParameterizableViewController; +import java.util.Map; + import org.w3c.dom.Element; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.parsing.BeanComponentDefinition; +import org.springframework.beans.factory.support.ManagedMap; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.beans.factory.xml.BeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; +import org.springframework.web.servlet.mvc.ParameterizableViewController; +import org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter; + /** * {@link org.springframework.beans.factory.xml.BeanDefinitionParser} that parses a * {@code view-controller} element to register a {@link ParameterizableViewController}. + * Will also register a {@link SimpleUrlHandlerMapping} for view controllers. * - * @author Rossen Stoyanchev + * @author Keith Donald + * @author Christian Dupuis * @since 3.0 - * @see MvcViewControllers - * @see MvcViewControllersExecutor */ -class ViewControllerBeanDefinitionParser extends AbstractSpecificationBeanDefinitionParser { +class ViewControllerBeanDefinitionParser implements BeanDefinitionParser { - /** - * Parses the {@code } tag. - */ - public FeatureSpecification doParse(Element element, ParserContext parserContext) { - String path = element.getAttribute("path"); - String viewName = element.getAttribute("view-name"); - return new MvcViewControllers(path, viewName.isEmpty() ? null : viewName); + private static final String HANDLER_ADAPTER_BEAN_NAME = + "org.springframework.web.servlet.config.viewControllerHandlerAdapter"; + + private static final String HANDLER_MAPPING_BEAN_NAME = + "org.springframework.web.servlet.config.viewControllerHandlerMapping"; + + + public BeanDefinition parse(Element element, ParserContext parserContext) { + Object source = parserContext.extractSource(element); + + // Register handler adapter + registerHanderAdapter(parserContext, source); + + // Register handler mapping + BeanDefinition handlerMappingDef = registerHandlerMapping(parserContext, source); + + // Create view controller bean definition + RootBeanDefinition viewControllerDef = new RootBeanDefinition(ParameterizableViewController.class); + viewControllerDef.setSource(source); + if (element.hasAttribute("view-name")) { + viewControllerDef.getPropertyValues().add("viewName", element.getAttribute("view-name")); + } + Map urlMap; + if (handlerMappingDef.getPropertyValues().contains("urlMap")) { + urlMap = (Map) handlerMappingDef.getPropertyValues().getPropertyValue("urlMap").getValue(); + } + else { + urlMap = new ManagedMap(); + handlerMappingDef.getPropertyValues().add("urlMap", urlMap); + } + urlMap.put(element.getAttribute("path"), viewControllerDef); + return null; + } + + private void registerHanderAdapter(ParserContext parserContext, Object source) { + if (!parserContext.getRegistry().containsBeanDefinition(HANDLER_ADAPTER_BEAN_NAME)) { + RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(SimpleControllerHandlerAdapter.class); + handlerAdapterDef.setSource(source); + handlerAdapterDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + parserContext.getRegistry().registerBeanDefinition(HANDLER_ADAPTER_BEAN_NAME, handlerAdapterDef); + parserContext.registerComponent(new BeanComponentDefinition(handlerAdapterDef, HANDLER_ADAPTER_BEAN_NAME)); + } + } + + private BeanDefinition registerHandlerMapping(ParserContext parserContext, Object source) { + if (!parserContext.getRegistry().containsBeanDefinition(HANDLER_MAPPING_BEAN_NAME)) { + RootBeanDefinition handlerMappingDef = new RootBeanDefinition(SimpleUrlHandlerMapping.class); + handlerMappingDef.setSource(source); + handlerMappingDef.getPropertyValues().add("order", "1"); + handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + parserContext.getRegistry().registerBeanDefinition(HANDLER_MAPPING_BEAN_NAME, handlerMappingDef); + parserContext.registerComponent(new BeanComponentDefinition(handlerMappingDef, HANDLER_MAPPING_BEAN_NAME)); + return handlerMappingDef; + } + else { + return parserContext.getRegistry().getBeanDefinition(HANDLER_MAPPING_BEAN_NAME); + } } } diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcAnnotationDrivenFeatureTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcAnnotationDrivenFeatureTests.java deleted file mode 100644 index 21fb0ae64f0..00000000000 --- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcAnnotationDrivenFeatureTests.java +++ /dev/null @@ -1,107 +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.web.servlet.config; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import java.util.List; - -import org.junit.Test; -import org.springframework.beans.DirectFieldAccessor; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Feature; -import org.springframework.context.annotation.FeatureConfiguration; -import org.springframework.format.support.DefaultFormattingConversionService; -import org.springframework.format.support.FormattingConversionService; -import org.springframework.http.converter.HttpMessageConverter; -import org.springframework.http.converter.StringHttpMessageConverter; -import org.springframework.validation.MessageCodesResolver; -import org.springframework.validation.Validator; -import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; -import org.springframework.web.bind.support.ConfigurableWebBindingInitializer; -import org.springframework.web.method.support.HandlerMethodArgumentResolver; -import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMethodAdapter; -import org.springframework.web.servlet.mvc.method.annotation.support.ServletWebArgumentResolverAdapter; - -/** - * Integration tests for the {@link MvcAnnotationDriven} feature specification. - * @author Rossen Stoyanchev - * @author Chris Beams - * @since 3.1 - */ -public class MvcAnnotationDrivenFeatureTests { - - @SuppressWarnings("unchecked") - @Test - public void testMessageCodesResolver() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); - ctx.register(MvcFeature.class, MvcBeans.class); - ctx.refresh(); - RequestMappingHandlerMethodAdapter adapter = ctx.getBean(RequestMappingHandlerMethodAdapter.class); - assertNotNull(adapter); - Object initializer = new DirectFieldAccessor(adapter).getPropertyValue("webBindingInitializer"); - assertNotNull(initializer); - MessageCodesResolver resolver = ((ConfigurableWebBindingInitializer) initializer).getMessageCodesResolver(); - assertNotNull(resolver); - assertEquals("test.foo.bar", resolver.resolveMessageCodes("foo", "bar")[0]); - Object value = new DirectFieldAccessor(adapter).getPropertyValue("customArgumentResolvers"); - assertNotNull(value); - List resolvers = (List) value; - assertEquals(2, resolvers.size()); - assertTrue(resolvers.get(0) instanceof ServletWebArgumentResolverAdapter); - assertTrue(resolvers.get(1) instanceof TestHandlerMethodArgumentResolver); - Object converters = new DirectFieldAccessor(adapter).getPropertyValue("messageConverters"); - assertNotNull(converters); - List> convertersArray = (List>) converters; - assertTrue("Default converters are registered in addition to the custom one", convertersArray.size() > 1); - assertTrue(convertersArray.get(0) instanceof StringHttpMessageConverter); - } - -} - -@FeatureConfiguration -class MvcFeature { - @Feature - public MvcAnnotationDriven annotationDriven(MvcBeans mvcBeans) { - return new MvcAnnotationDriven() - .conversionService(mvcBeans.conversionService()) - .messageCodesResolver(mvcBeans.messageCodesResolver()) - .validator(mvcBeans.validator()) - .messageConverters(new StringHttpMessageConverter()) - .argumentResolvers(new TestWebArgumentResolver()) - .argumentResolvers(new TestHandlerMethodArgumentResolver()); - } -} - -@Configuration -class MvcBeans { - @Bean - public FormattingConversionService conversionService() { - return new DefaultFormattingConversionService(); - } - @Bean - public Validator validator() { - return new LocalValidatorFactoryBean(); - } - @Bean MessageCodesResolver messageCodesResolver() { - return new TestMessageCodesResolver(); - } -} - diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcDefaultServletHandlerTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcDefaultServletHandlerTests.java deleted file mode 100644 index 74317c6bb88..00000000000 --- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcDefaultServletHandlerTests.java +++ /dev/null @@ -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.web.servlet.config; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - -import org.junit.Test; -import org.springframework.beans.DirectFieldAccessor; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.context.annotation.Feature; -import org.springframework.context.annotation.FeatureConfiguration; -import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter; -import org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler; - -/** - * Test fixture for {@link MvcDefaultServletHandler} feature specification. - * @author Rossen Stoyanchev - * @since 3.1 - */ -public class MvcDefaultServletHandlerTests { - - @Test - public void testDefaultServletHandler() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); - ctx.register(MvcDefaultServletHandlerFeature.class); - ctx.refresh(); - HttpRequestHandlerAdapter adapter = ctx.getBean(HttpRequestHandlerAdapter.class); - assertNotNull(adapter); - DefaultServletHttpRequestHandler handler = ctx.getBean(DefaultServletHttpRequestHandler.class); - assertNotNull(handler); - String defaultServletHandlerName = (String) new DirectFieldAccessor(handler) - .getPropertyValue("defaultServletName"); - assertEquals("foo", defaultServletHandlerName); - } - - @FeatureConfiguration - private static class MvcDefaultServletHandlerFeature { - - @SuppressWarnings("unused") - @Feature - public MvcDefaultServletHandler defaultServletHandler() { - return new MvcDefaultServletHandler("foo"); - } - - } - -} diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcInterceptorsTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcInterceptorsTests.java deleted file mode 100644 index 6f3e42cf10b..00000000000 --- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcInterceptorsTests.java +++ /dev/null @@ -1,126 +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.web.servlet.config; - -import static org.easymock.EasyMock.capture; -import static org.easymock.EasyMock.createMock; -import static org.easymock.EasyMock.replay; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import java.util.Iterator; - -import org.easymock.Capture; -import org.junit.Test; -import org.springframework.beans.factory.parsing.Problem; -import org.springframework.beans.factory.parsing.ProblemReporter; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.context.annotation.Feature; -import org.springframework.context.annotation.FeatureConfiguration; -import org.springframework.web.servlet.HandlerInterceptor; -import org.springframework.web.servlet.handler.MappedInterceptor; -import org.springframework.web.servlet.handler.UserRoleAuthorizationInterceptor; -import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; -import org.springframework.web.servlet.theme.ThemeChangeInterceptor; - -/** - * Test fixture for {@link MvcInterceptors}. - * @author Rossen Stoyanchev - */ -public class MvcInterceptorsTests { - - @Test - public void testInterceptors() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); - ctx.register(MvcInterceptorsFeature.class); - ctx.refresh(); - - Iterator itr = ctx.getBeansOfType(MappedInterceptor.class).values().iterator(); - - MappedInterceptor interceptor = itr.next(); - assertTrue(interceptor.getInterceptor() instanceof UserRoleAuthorizationInterceptor); - assertNull(interceptor.getPathPatterns()); - - interceptor = itr.next(); - assertTrue(interceptor.getInterceptor() instanceof LocaleChangeInterceptor); - assertArrayEquals(new String[] { "/locale", "/locale/**" }, interceptor.getPathPatterns()); - - interceptor = itr.next(); - assertTrue(interceptor.getInterceptor() instanceof ThemeChangeInterceptor); - assertArrayEquals(new String[] { "/theme", "/theme/**" }, interceptor.getPathPatterns()); - - } - - @Test - public void validateNoInterceptors() { - ProblemReporter reporter = createMock(ProblemReporter.class); - Capture captured = new Capture(); - reporter.error(capture(captured)); - replay(reporter); - - boolean result = new MvcInterceptors().validate(reporter); - - assertFalse(result); - assertEquals("No interceptors defined.", captured.getValue().getMessage()); - } - - @Test - public void validateNullHandler() { - ProblemReporter reporter = createMock(ProblemReporter.class); - Capture captured = new Capture(); - reporter.error(capture(captured)); - replay(reporter); - - HandlerInterceptor[] interceptors = new HandlerInterceptor[] { null }; - boolean result = new MvcInterceptors().globalInterceptors(interceptors).validate(reporter); - - assertFalse(result); - assertTrue(captured.getValue().getMessage().contains("Null interceptor")); - } - - @Test - public void validateEmptyPath() { - ProblemReporter reporter = createMock(ProblemReporter.class); - Capture captured = new Capture(); - reporter.error(capture(captured)); - replay(reporter); - - HandlerInterceptor[] interceptors = new HandlerInterceptor[] { new LocaleChangeInterceptor() }; - String[] patterns = new String[] { "" }; - boolean result = new MvcInterceptors().mappedInterceptors(patterns, interceptors).validate(reporter); - - assertFalse(result); - assertTrue(captured.getValue().getMessage().startsWith("Empty path pattern specified for ")); - } - - @FeatureConfiguration - private static class MvcInterceptorsFeature { - - @SuppressWarnings("unused") - @Feature - public MvcInterceptors interceptors() { - return new MvcInterceptors() - .globalInterceptors(new UserRoleAuthorizationInterceptor()) - .mappedInterceptors(new String[] { "/locale", "/locale/**" }, new LocaleChangeInterceptor()) - .mappedInterceptors(new String[] { "/theme", "/theme/**"}, new ThemeChangeInterceptor()); - } - - } - -} diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcResourcesTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcResourcesTests.java deleted file mode 100644 index bf71da49afa..00000000000 --- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcResourcesTests.java +++ /dev/null @@ -1,98 +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.web.servlet.config; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.util.List; - -import org.junit.Test; -import org.springframework.beans.DirectFieldAccessor; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.context.annotation.Feature; -import org.springframework.context.annotation.FeatureConfiguration; -import org.springframework.core.io.Resource; -import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; -import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter; -import org.springframework.web.servlet.resource.ResourceHttpRequestHandler; - -/** - * Test fixture for {@link MvcResources} feature specification. - * @author Rossen Stoyanchev - * @since 3.1 - */ -public class MvcResourcesTests { - - @Test - public void testResources() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); - ctx.register(MvcResourcesFeature.class); - ctx.refresh(); - HttpRequestHandlerAdapter adapter = ctx.getBean(HttpRequestHandlerAdapter.class); - assertNotNull(adapter); - ResourceHttpRequestHandler handler = ctx.getBean(ResourceHttpRequestHandler.class); - assertNotNull(handler); - @SuppressWarnings("unchecked") - List locations = (List) new DirectFieldAccessor(handler).getPropertyValue("locations"); - assertNotNull(locations); - assertEquals(2, locations.size()); - assertEquals("foo", locations.get(0).getFilename()); - assertEquals("bar", locations.get(1).getFilename()); - SimpleUrlHandlerMapping mapping = ctx.getBean(SimpleUrlHandlerMapping.class); - assertEquals(1, mapping.getOrder()); - assertSame(handler, mapping.getHandlerMap().get("/resources/**")); - } - - @Test - public void testInvalidResources() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); - ctx.register(InvalidMvcResourcesFeature.class); - try { - ctx.refresh(); - fail("Invalid feature spec should not validate"); - } catch (RuntimeException e) { - assertTrue(e.getCause().getMessage().contains("Mapping is required")); - // TODO : should all problems be in the message ? - } - } - - @FeatureConfiguration - private static class MvcResourcesFeature { - - @SuppressWarnings("unused") - @Feature - public MvcResources resources() { - return new MvcResources("/resources/**", new String[] { "/foo", "/bar" }).cachePeriod(86400).order(1); - } - - } - - @FeatureConfiguration - private static class InvalidMvcResourcesFeature { - - @SuppressWarnings("unused") - @Feature - public MvcResources resources() { - return new MvcResources(" ", new String[] {}); - } - - } - -} diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcViewControllersTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcViewControllersTests.java deleted file mode 100644 index fdb27d71557..00000000000 --- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcViewControllersTests.java +++ /dev/null @@ -1,131 +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.web.servlet.config; - -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.util.Map; - -import org.junit.Test; -import org.springframework.beans.factory.parsing.FailFastProblemReporter; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.context.annotation.Feature; -import org.springframework.context.annotation.FeatureConfiguration; -import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; -import org.springframework.web.servlet.mvc.ParameterizableViewController; -import org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter; - -/** - * Test fixture for {@link MvcViewControllers} feature specification. - * @author Rossen Stoyanchev - * @since 3.1 - */ -public class MvcViewControllersTests { - - @Test - public void testMvcViewControllers() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); - ctx.register(MvcViewControllersFeature.class); - ctx.refresh(); - SimpleControllerHandlerAdapter adapter = ctx.getBean(SimpleControllerHandlerAdapter.class); - assertNotNull(adapter); - SimpleUrlHandlerMapping handler = ctx.getBean(SimpleUrlHandlerMapping.class); - assertNotNull(handler); - Map urlMap = handler.getUrlMap(); - assertNotNull(urlMap); - assertEquals(2, urlMap.size()); - ParameterizableViewController controller = (ParameterizableViewController) urlMap.get("/"); - assertNotNull(controller); - assertEquals("home", controller.getViewName()); - controller = (ParameterizableViewController) urlMap.get("/account"); - assertNotNull(controller); - assertNull(controller.getViewName()); - } - - @Test - public void testEmptyPath() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); - ctx.register(EmptyPathViewControllersFeature.class); - try { - ctx.refresh(); - fail("expected exception"); - } catch (Exception ex) { - assertTrue(ex.getCause().getMessage().contains("path attribute")); - } - } - - @Test - public void testEmptyViewName() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); - ctx.register(EmptyViewNameViewControllersFeature.class); - try { - ctx.refresh(); - fail("expected exception"); - } catch (Exception ex) { - assertTrue(ex.getCause().getMessage().contains("not empty")); - } - } - - @Test - public void testNullViewName() { - FailFastProblemReporter problemReporter = new FailFastProblemReporter(); - assertThat(new MvcViewControllers("/some/path").validate(problemReporter), is(true)); - } - - - @FeatureConfiguration - private static class MvcViewControllersFeature { - - @SuppressWarnings("unused") - @Feature - public MvcViewControllers mvcViewControllers() { - return new MvcViewControllers("/", "home").viewController("/account"); - } - - } - - - @FeatureConfiguration - private static class EmptyViewNameViewControllersFeature { - - @SuppressWarnings("unused") - @Feature - public MvcViewControllers mvcViewControllers() { - return new MvcViewControllers("/some/path", ""); - } - - } - - - @FeatureConfiguration - private static class EmptyPathViewControllersFeature { - - @SuppressWarnings("unused") - @Feature - public MvcViewControllers mvcViewControllers() { - return new MvcViewControllers("", "someViewName"); - } - - } - -} -