Introduce FeatureSpecification support
Introduce FeatureSpecification interface and implementations
FeatureSpecification objects decouple the configuration of
spring container features from the concern of parsing XML
namespaces, allowing for reuse in code-based configuration
(see @Feature* annotations below).
* ComponentScanSpec
* TxAnnotationDriven
* MvcAnnotationDriven
* MvcDefaultServletHandler
* MvcResources
* MvcViewControllers
Refactor associated BeanDefinitionParsers to delegate to new impls above
The following BeanDefinitionParser implementations now deal only
with the concern of XML parsing. Validation is handled by their
corresponding FeatureSpecification object. Bean definition creation
and registration is handled by their corresponding
FeatureSpecificationExecutor type.
* ComponentScanBeanDefinitionParser
* AnnotationDrivenBeanDefinitionParser (tx)
* AnnotationDrivenBeanDefinitionParser (mvc)
* DefaultServletHandlerBeanDefinitionParser
* ResourcesBeanDefinitionParser
* ViewControllerBeanDefinitionParser
Update AopNamespaceUtils to decouple from XML (DOM API)
Methods necessary for executing TxAnnotationDriven specification
(and eventually, the AspectJAutoProxy specification) have been
added that accept boolean arguments for whether to proxy
target classes and whether to expose the proxy via threadlocal.
Methods that accepted and introspected DOM Element objects still
exist but have been deprecated.
Introduce @FeatureConfiguration classes and @Feature methods
Allow for creation and configuration of FeatureSpecification objects
at the user level. A companion for @Configuration classes allowing
for completely code-driven configuration of the Spring container.
See changes in ConfigurationClassPostProcessor for implementation
details.
See Feature*Tests for usage examples.
FeatureTestSuite in .integration-tests is a JUnit test suite designed
to aggregate all BDP and Feature* related tests for a convenient way
to confirm that Feature-related changes don't break anything.
Uncomment this test and execute from Eclipse / IDEA. Due to classpath
issues, this cannot be compiled by Ant/Ivy at the command line.
Introduce @FeatureAnnotation meta-annotation and @ComponentScan impl
@FeatureAnnotation provides an alternate mechanism for creating
and executing FeatureSpecification objects. See @ComponentScan
and its corresponding ComponentScanAnnotationParser implementation
for details. See ComponentScanAnnotationIntegrationTests for usage
examples
Introduce Default[Formatting]ConversionService implementations
Allows for convenient instantiation of ConversionService objects
containing defaults appropriate for most environments. Replaces
similar support originally in ConversionServiceFactory (which is now
deprecated). This change was justified by the need to avoid use
of FactoryBeans in @Configuration classes (such as
FormattingConversionServiceFactoryBean). It is strongly preferred
that users simply instantiate and configure the objects that underlie
our FactoryBeans. In the case of the ConversionService types, the
easiest way to do this is to create Default* subtypes. This also
follows convention with the rest of the framework.
Minor updates to util classes
All in service of changes above. See diffs for self-explanatory
details.
* BeanUtils
* ObjectUtils
* ReflectionUtils
This commit is contained in:
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* 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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,264 +18,86 @@ package org.springframework.web.servlet.config;
|
||||
|
||||
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.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.context.config.ExecutorContext;
|
||||
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.servlet.handler.ConversionServiceExposingInterceptor;
|
||||
import org.springframework.web.servlet.handler.MappedInterceptor;
|
||||
import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter;
|
||||
import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver;
|
||||
import org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping;
|
||||
import org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver;
|
||||
import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* {@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.
|
||||
*
|
||||
* <p>Responsible for:
|
||||
* <ol>
|
||||
* <li>Registering a DefaultAnnotationHandlerMapping bean for mapping HTTP Servlet Requests to @Controller methods
|
||||
* using @RequestMapping annotations.
|
||||
* <li>Registering a AnnotationMethodHandlerAdapter bean for invoking annotated @Controller methods.
|
||||
* Will configure the HandlerAdapter's <code>webBindingInitializer</code> property for centrally configuring
|
||||
* {@code @Controller} {@code DataBinder} instances:
|
||||
* <ul>
|
||||
* <li>Configures the conversionService if specified, otherwise defaults to a fresh {@link ConversionService} instance
|
||||
* created by the default {@link FormattingConversionServiceFactoryBean}.
|
||||
* <li>Configures the validator if specified, otherwise defaults to a fresh {@link Validator} instance created by the
|
||||
* default {@link LocalValidatorFactoryBean} <em>if the JSR-303 API is present on the classpath</em>.
|
||||
* <li>Configures standard {@link org.springframework.http.converter.HttpMessageConverter HttpMessageConverters},
|
||||
* including the {@link Jaxb2RootElementHttpMessageConverter} <em>if JAXB2 is present on the classpath</em>, and
|
||||
* the {@link MappingJacksonHttpMessageConverter} <em>if Jackson is present on the classpath</em>.
|
||||
* </ul>
|
||||
* </ol>
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Juergen Hoeller
|
||||
* @author Arjen Poutsma
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.0
|
||||
* @see MvcAnnotationDriven
|
||||
* @see MvcAnnotationDrivenExecutor
|
||||
*/
|
||||
class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
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());
|
||||
|
||||
|
||||
/**
|
||||
* Parses the {@code <mvc:annotation-driven/>} tag.
|
||||
*/
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
Object source = parserContext.extractSource(element);
|
||||
|
||||
CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source);
|
||||
parserContext.pushContainingComponent(compDefinition);
|
||||
|
||||
RootBeanDefinition annMappingDef = new RootBeanDefinition(DefaultAnnotationHandlerMapping.class);
|
||||
annMappingDef.setSource(source);
|
||||
annMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
annMappingDef.getPropertyValues().add("order", 0);
|
||||
String annMappingName = parserContext.getReaderContext().registerWithGeneratedName(annMappingDef);
|
||||
|
||||
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 annAdapterDef = new RootBeanDefinition(AnnotationMethodHandlerAdapter.class);
|
||||
annAdapterDef.setSource(source);
|
||||
annAdapterDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
annAdapterDef.getPropertyValues().add("webBindingInitializer", bindingDef);
|
||||
annAdapterDef.getPropertyValues().add("messageConverters", messageConverters);
|
||||
if (argumentResolvers != null) {
|
||||
annAdapterDef.getPropertyValues().add("customArgumentResolvers", argumentResolvers);
|
||||
}
|
||||
String annAdapterName = parserContext.getReaderContext().registerWithGeneratedName(annAdapterDef);
|
||||
|
||||
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 annExceptionResolver = new RootBeanDefinition(AnnotationMethodHandlerExceptionResolver.class);
|
||||
annExceptionResolver.setSource(source);
|
||||
annExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
annExceptionResolver.getPropertyValues().add("messageConverters", messageConverters);
|
||||
annExceptionResolver.getPropertyValues().add("order", 0);
|
||||
String annExceptionResolverName =
|
||||
parserContext.getReaderContext().registerWithGeneratedName(annExceptionResolver);
|
||||
|
||||
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(annMappingDef, annMappingName));
|
||||
parserContext.registerComponent(new BeanComponentDefinition(annAdapterDef, annAdapterName));
|
||||
parserContext.registerComponent(new BeanComponentDefinition(annExceptionResolver, annExceptionResolverName));
|
||||
parserContext.registerComponent(new BeanComponentDefinition(responseStatusExceptionResolver, responseStatusExceptionResolverName));
|
||||
parserContext.registerComponent(new BeanComponentDefinition(defaultExceptionResolver, defaultExceptionResolverName));
|
||||
parserContext.registerComponent(new BeanComponentDefinition(mappedCsInterceptorDef, mappedInterceptorName));
|
||||
parserContext.popAndRegisterContainingComponent();
|
||||
|
||||
MvcAnnotationDriven spec = createSpecification(element, parserContext);
|
||||
spec.execute(createExecutorContext(parserContext));
|
||||
return null;
|
||||
}
|
||||
|
||||
private RuntimeBeanReference getConversionService(Element element, Object source, ParserContext parserContext) {
|
||||
RuntimeBeanReference conversionServiceRef;
|
||||
|
||||
private MvcAnnotationDriven createSpecification(Element element, ParserContext parserContext) {
|
||||
MvcAnnotationDriven spec = new MvcAnnotationDriven();
|
||||
if (element.hasAttribute("conversion-service")) {
|
||||
conversionServiceRef = new RuntimeBeanReference(element.getAttribute("conversion-service"));
|
||||
String conversionService = element.getAttribute("conversion-service");
|
||||
spec.conversionService(conversionService);
|
||||
}
|
||||
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")) {
|
||||
return new RuntimeBeanReference(element.getAttribute("validator"));
|
||||
spec.validator(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")) {
|
||||
return new RuntimeBeanReference(element.getAttribute("message-codes-resolver"));
|
||||
} else {
|
||||
return null;
|
||||
spec.messageCodesResolver(element.getAttribute("message-codes-resolver"));
|
||||
}
|
||||
}
|
||||
|
||||
private ManagedList<?> getArgumentResolvers(Element element, Object source, ParserContext parserContext) {
|
||||
Element resolversElement = DomUtils.getChildElementByTagName(element, "argument-resolvers");
|
||||
if (resolversElement != null) {
|
||||
ManagedList<BeanDefinitionHolder> argumentResolvers = new ManagedList<BeanDefinitionHolder>();
|
||||
argumentResolvers.setSource(source);
|
||||
for (Element resolver : DomUtils.getChildElementsByTagName(resolversElement, "bean")) {
|
||||
BeanDefinitionHolder beanDef = parserContext.getDelegate().parseBeanDefinitionElement(resolver);
|
||||
beanDef = parserContext.getDelegate().decorateBeanDefinitionIfRequired(resolver, beanDef);
|
||||
argumentResolvers.add(beanDef);
|
||||
}
|
||||
return argumentResolvers;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private ManagedList<?> getMessageConverters(Element element, Object source, ParserContext parserContext) {
|
||||
Element convertersElement = DomUtils.getChildElementByTagName(element, "message-converters");
|
||||
if (convertersElement != null) {
|
||||
ManagedList<BeanDefinitionHolder> messageConverters = new ManagedList<BeanDefinitionHolder>();
|
||||
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);
|
||||
if (convertersElement.hasAttribute("register-defaults")) {
|
||||
spec.shouldRegisterDefaultMessageConverters(Boolean.valueOf(convertersElement
|
||||
.getAttribute("register-defaults")));
|
||||
}
|
||||
return messageConverters;
|
||||
} else {
|
||||
ManagedList<RootBeanDefinition> messageConverters = new ManagedList<RootBeanDefinition>();
|
||||
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;
|
||||
spec.messageConverters(extractBeanSubElements(convertersElement, parserContext));
|
||||
}
|
||||
Element resolversElement = DomUtils.getChildElementByTagName(element, "argument-resolvers");
|
||||
if (resolversElement != null) {
|
||||
spec.argumentResolvers(extractBeanSubElements(resolversElement, parserContext));
|
||||
}
|
||||
|
||||
spec.source(parserContext.extractSource(element));
|
||||
spec.sourceName(element.getTagName());
|
||||
return spec;
|
||||
}
|
||||
|
||||
private RootBeanDefinition createConverterBeanDefinition(Class<? extends HttpMessageConverter> converterClass,
|
||||
Object source) {
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(converterClass);
|
||||
beanDefinition.setSource(source);
|
||||
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
|
||||
return beanDefinition;
|
||||
private ManagedList<? super Object> extractBeanSubElements(Element parentElement, ParserContext parserContext) {
|
||||
ManagedList<? super Object> list = new ManagedList<Object>();
|
||||
list.setSource(parserContext.extractSource(parentElement));
|
||||
for (Element beanElement : DomUtils.getChildElementsByTagName(parentElement, "bean")) {
|
||||
BeanDefinitionHolder beanDef = parserContext.getDelegate().parseBeanDefinitionElement(beanElement);
|
||||
beanDef = parserContext.getDelegate().decorateBeanDefinitionIfRequired(beanElement, beanDef);
|
||||
list.add(beanDef);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapt the given ParserContext instance into an ExecutorContext.
|
||||
*
|
||||
* TODO SPR-7420: consider unifying the two through a superinterface.
|
||||
* TODO SPR-7420: create a common ParserContext-to-ExecutorContext adapter util
|
||||
*/
|
||||
private ExecutorContext createExecutorContext(ParserContext parserContext) {
|
||||
ExecutorContext executorContext = new ExecutorContext();
|
||||
executorContext.setRegistry(parserContext.getRegistry());
|
||||
executorContext.setRegistrar(parserContext);
|
||||
executorContext.setProblemReporter(parserContext.getReaderContext().getProblemReporter());
|
||||
return executorContext;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,20 +16,15 @@
|
||||
|
||||
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.ExecutorContext;
|
||||
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
|
||||
@@ -37,37 +32,39 @@ import org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler
|
||||
* {@link SimpleUrlHandlerMapping} for mapping resource requests, and a
|
||||
* {@link HttpRequestHandlerAdapter} if necessary.
|
||||
*
|
||||
* @author Jeremy Grelle
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.0.4
|
||||
*/
|
||||
class DefaultServletHandlerBeanDefinitionParser extends AbstractHttpRequestHandlerBeanDefinitionParser {
|
||||
class DefaultServletHandlerBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
@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<String, String> urlMap = new ManagedMap<String, String>();
|
||||
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));
|
||||
/**
|
||||
* Parses the {@code <mvc:default-servlet-handler/>} tag.
|
||||
*/
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
MvcDefaultServletHandler spec = createSpecification(element, parserContext);
|
||||
spec.execute(createExecutorContext(parserContext));
|
||||
return null;
|
||||
}
|
||||
|
||||
private MvcDefaultServletHandler createSpecification(Element element, ParserContext parserContext) {
|
||||
String defaultServletHandler = element.getAttribute("default-servlet-handler");
|
||||
MvcDefaultServletHandler spec = StringUtils.hasText(defaultServletHandler) ? new MvcDefaultServletHandler(
|
||||
defaultServletHandler) : new MvcDefaultServletHandler();
|
||||
return spec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapt the given ParserContext instance into an ExecutorContext.
|
||||
*
|
||||
* TODO SPR-7420: consider unifying the two through a superinterface.
|
||||
* TODO SPR-7420: create a common ParserContext-to-ExecutorContext adapter util
|
||||
*/
|
||||
private ExecutorContext createExecutorContext(ParserContext parserContext) {
|
||||
ExecutorContext executorContext = new ExecutorContext();
|
||||
executorContext.setRegistry(parserContext.getRegistry());
|
||||
executorContext.setRegistrar(parserContext);
|
||||
executorContext.setProblemReporter(parserContext.getReaderContext().getProblemReporter());
|
||||
return executorContext;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* 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.SimpleProblemCollector;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Specifies the Spring MVC "annotation-driven" container feature. The
|
||||
* feature provides the following fine-grained configuration:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@code DefaultAnnotationHandlerMapping} bean for mapping HTTP Servlet Requests
|
||||
* to {@code @Controller} methods using {@code @RequestMapping} annotations.
|
||||
* <li>{@code AnnotationMethodHandlerAdapter} bean for invoking annotated
|
||||
* {@code @Controller} methods.
|
||||
* <li>{@code HandlerExceptionResolver} beans for invoking {@code @ExceptionHandler}
|
||||
* controller methods and for mapping Spring exception to HTTP status codes.
|
||||
* </ul>
|
||||
*
|
||||
* <p>The {@code HandlerAdapter} is further configured with the following, which apply
|
||||
* globally (across controllers invoked though the {@code AnnotationMethodHandlerAdapter}):
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@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}.
|
||||
* <li>{@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} <em>assuming
|
||||
* JSR-303 API is present on the classpath</em>.
|
||||
* <li>{@code HttpMessageConverter} beans including the {@link
|
||||
* Jaxb2RootElementHttpMessageConverter} <em>assuming JAXB2 is present on the
|
||||
* classpath</em>, the {@link MappingJacksonHttpMessageConverter} <em>assuming Jackson
|
||||
* is present on the classpath</em>, and the {@link AtomFeedHttpMessageConverter} and the
|
||||
* {@link RssChannelHttpMessageConverter} converters <em>assuming Rome is present on
|
||||
* the classpath</em>.
|
||||
* <li>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.
|
||||
* </ul>
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
*/
|
||||
public final class MvcAnnotationDriven extends AbstractFeatureSpecification {
|
||||
|
||||
private static final Class<? extends FeatureSpecificationExecutor> EXECUTOR_TYPE = MvcAnnotationDrivenExecutor.class;
|
||||
|
||||
private Object conversionService;
|
||||
|
||||
private Object validator;
|
||||
|
||||
private Object messageCodesResolver;
|
||||
|
||||
private boolean shouldRegisterDefaultMessageConverters = true;
|
||||
|
||||
private ManagedList<? super Object> messageConverters = new ManagedList<Object>();
|
||||
|
||||
private ManagedList<? super Object> argumentResolvers = new ManagedList<Object>();
|
||||
|
||||
/**
|
||||
* Creates an MvcAnnotationDriven specification.
|
||||
*/
|
||||
public MvcAnnotationDriven() {
|
||||
super(EXECUTOR_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p> 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.
|
||||
*
|
||||
* <p> 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p> 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<? super Object> messageConverters) {
|
||||
this.messageConverters = messageConverters;
|
||||
}
|
||||
|
||||
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(WebArgumentResolver... resolvers) {
|
||||
for (WebArgumentResolver resolver : resolvers) {
|
||||
this.argumentResolvers.add(resolver);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
void argumentResolvers(ManagedList<? super Object> argumentResolvers) {
|
||||
this.argumentResolvers = argumentResolvers;
|
||||
}
|
||||
|
||||
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.
|
||||
*
|
||||
* <p> 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(SimpleProblemCollector reporter) {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* 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.ExecutorContext;
|
||||
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.AnnotationMethodHandlerAdapter;
|
||||
import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver;
|
||||
import org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping;
|
||||
import org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver;
|
||||
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<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());
|
||||
|
||||
@Override
|
||||
public void doExecute(MvcAnnotationDriven spec, ExecutorContext executorContext) {
|
||||
ComponentRegistrar registrar = executorContext.getRegistrar();
|
||||
Object source = spec.source();
|
||||
|
||||
RootBeanDefinition annMappingDef = new RootBeanDefinition(DefaultAnnotationHandlerMapping.class);
|
||||
annMappingDef.setSource(source);
|
||||
annMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
annMappingDef.getPropertyValues().add("order", 0);
|
||||
String annMappingName = registrar.registerWithGeneratedName(annMappingDef);
|
||||
|
||||
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<? super Object> messageConverters = getMessageConverters(spec, registrar);
|
||||
|
||||
RootBeanDefinition annAdapterDef = new RootBeanDefinition(AnnotationMethodHandlerAdapter.class);
|
||||
annAdapterDef.setSource(source);
|
||||
annAdapterDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
annAdapterDef.getPropertyValues().add("webBindingInitializer", bindingDef);
|
||||
annAdapterDef.getPropertyValues().add("messageConverters", messageConverters);
|
||||
if (!spec.argumentResolvers().isEmpty()) {
|
||||
annAdapterDef.getPropertyValues().add("customArgumentResolvers", spec.argumentResolvers());
|
||||
}
|
||||
String annAdapterName = registrar.registerWithGeneratedName(annAdapterDef);
|
||||
|
||||
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 annExceptionResolver = new RootBeanDefinition(AnnotationMethodHandlerExceptionResolver.class);
|
||||
annExceptionResolver.setSource(source);
|
||||
annExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
annExceptionResolver.getPropertyValues().add("messageConverters", messageConverters);
|
||||
annExceptionResolver.getPropertyValues().add("order", 0);
|
||||
String annExceptionResolverName = registrar.registerWithGeneratedName(annExceptionResolver);
|
||||
|
||||
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(annMappingDef, annMappingName));
|
||||
compDefinition.addNestedComponent(new BeanComponentDefinition(annAdapterDef, annAdapterName));
|
||||
compDefinition.addNestedComponent(new BeanComponentDefinition(annExceptionResolver, annExceptionResolverName));
|
||||
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<? super Object> getMessageConverters(MvcAnnotationDriven spec, ComponentRegistrar registrar) {
|
||||
ManagedList<? super Object> messageConverters = new ManagedList<Object>();
|
||||
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<? extends HttpMessageConverter> 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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.SimpleProblemCollector;
|
||||
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:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link DefaultServletHttpRequestHandler} for serving static files by
|
||||
* forwarding to the Servlet container's "default" Servlet.
|
||||
* <li>{@link SimpleUrlHandlerMapping} to map the above request handler to "/**"
|
||||
* <li>{@link HttpRequestHandlerAdapter} to enable the DispatcherServlet to be
|
||||
* able to invoke the above request handler.
|
||||
* </ul>
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
*/
|
||||
public class MvcDefaultServletHandler extends AbstractFeatureSpecification {
|
||||
|
||||
private static final Class<? extends FeatureSpecificationExecutor> EXECUTOR_TYPE = MvcDefaultServletHandlerExecutor.class;
|
||||
|
||||
private String defaultServletName;
|
||||
|
||||
/**
|
||||
* <p>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.
|
||||
*
|
||||
* <p>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(SimpleProblemCollector reporter) {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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.ExecutorContext;
|
||||
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<MvcDefaultServletHandler> {
|
||||
|
||||
private static final String HANDLER_ADAPTER_BEAN_NAME = "org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter";
|
||||
|
||||
@Override
|
||||
protected void doExecute(MvcDefaultServletHandler spec, ExecutorContext executorContext) {
|
||||
BeanDefinitionRegistry registry = executorContext.getRegistry();
|
||||
ComponentRegistrar registrar = executorContext.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<String, String> urlMap = new ManagedMap<String, String>();
|
||||
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));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* 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.SimpleProblemCollector;
|
||||
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:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link ResourceHttpRequestHandler} to serve static resources from a
|
||||
* list of web-root relative, classpath, or other locations.
|
||||
* <li>{@link SimpleUrlHandlerMapping} to map the above request handler to a
|
||||
* a specific path pattern (e.g. "/resources/**").
|
||||
* <li>{@link HttpRequestHandlerAdapter} to enable the DispatcherServlet to be
|
||||
* able to invoke the above request handler.
|
||||
* </ul>
|
||||
*
|
||||
* @author Rossen Stoynchev
|
||||
* @since 3.1
|
||||
*/
|
||||
public final class MvcResources extends AbstractFeatureSpecification {
|
||||
|
||||
private static final Class<? extends FeatureSpecificationExecutor> 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.
|
||||
* <p>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.
|
||||
* <p>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(SimpleProblemCollector problems) {
|
||||
if (!StringUtils.hasText(mapping)) {
|
||||
problems.error("Mapping is required");
|
||||
}
|
||||
if (locations == null || locations.length == 0) {
|
||||
problems.error("At least one location is required");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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.ExecutorContext;
|
||||
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<MvcResources> {
|
||||
|
||||
private static final String HANDLER_ADAPTER_BEAN_NAME = "org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter";
|
||||
|
||||
@Override
|
||||
protected void doExecute(MvcResources spec, ExecutorContext executorContext) {
|
||||
BeanDefinitionRegistry registry = executorContext.getRegistry();
|
||||
ComponentRegistrar registrar = executorContext.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<String, String> urlMap = new ManagedMap<String, String>();
|
||||
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));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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.SimpleProblemCollector;
|
||||
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:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link ParameterizableViewController} for each path/view name pair.
|
||||
* <li>{@link SimpleUrlHandlerMapping} mapping each view controller to its path.
|
||||
* <li>{@link SimpleControllerHandlerAdapter} to enable the DispatcherServlet
|
||||
* to invoke the view controllers.
|
||||
* </ul>
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
*/
|
||||
public final class MvcViewControllers extends AbstractFeatureSpecification {
|
||||
|
||||
private static final Class<? extends FeatureSpecificationExecutor> EXECUTOR_TYPE = MvcViewControllersExecutor.class;
|
||||
|
||||
private Map<String, String> mappings = new HashMap<String, String>();
|
||||
|
||||
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<String, String> mappings() {
|
||||
return Collections.unmodifiableMap(mappings);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doValidate(SimpleProblemCollector 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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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.ExecutorContext;
|
||||
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<MvcViewControllers> {
|
||||
|
||||
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, ExecutorContext executorContext) {
|
||||
BeanDefinitionRegistry registry = executorContext.getRegistry();
|
||||
ComponentRegistrar registrar = executorContext.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<String, String> 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<String, BeanDefinition>());
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, BeanDefinition> urlMap = (Map<String, BeanDefinition>) handlerMappingBeanDef
|
||||
.getPropertyValues().getPropertyValue("urlMap").getValue();
|
||||
urlMap.put(entry.getKey(), viewControllerDef);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* 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.
|
||||
@@ -16,89 +16,72 @@
|
||||
|
||||
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.core.Ordered;
|
||||
import org.springframework.context.config.ExecutorContext;
|
||||
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;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.beans.factory.xml.BeanDefinitionParser} that parses a
|
||||
* {@code resources} element to register a {@link ResourceHttpRequestHandler}.
|
||||
* Will also register a {@link SimpleUrlHandlerMapping} for mapping resource requests,
|
||||
* and a {@link HttpRequestHandlerAdapter} if necessary.
|
||||
* {@code resources} element.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Jeremy Grelle
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.0.4
|
||||
* @see MvcResources
|
||||
* @see MvcResourcesExecutor
|
||||
*/
|
||||
class ResourcesBeanDefinitionParser extends AbstractHttpRequestHandlerBeanDefinitionParser implements BeanDefinitionParser {
|
||||
class ResourcesBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
@Override
|
||||
public void doParse(Element element, ParserContext parserContext) {
|
||||
Object source = parserContext.extractSource(element);
|
||||
registerResourceMappings(parserContext, element, source);
|
||||
/**
|
||||
* Parses the {@code <mvc:resources/>} tag
|
||||
*/
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
MvcResources spec = createSpecification(element, parserContext);
|
||||
if (spec != null) {
|
||||
spec.execute(createExecutorContext(parserContext));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void registerResourceMappings(ParserContext parserContext, Element element, Object source) {
|
||||
String resourceHandlerName = registerResourceHandler(parserContext, element, source);
|
||||
if (resourceHandlerName == null) {
|
||||
return;
|
||||
|
||||
private MvcResources createSpecification(Element element, ParserContext parserContext) {
|
||||
String mapping = element.getAttribute("mapping");
|
||||
if (!StringUtils.hasText(mapping)) {
|
||||
parserContext.getReaderContext().error("The 'mapping' attribute is required.",
|
||||
parserContext.extractSource(element));
|
||||
return null;
|
||||
}
|
||||
|
||||
Map<String, String> urlMap = new ManagedMap<String, String>();
|
||||
String resourceRequestPath = element.getAttribute("mapping");
|
||||
if (!StringUtils.hasText(resourceRequestPath)) {
|
||||
parserContext.getReaderContext().error("The 'mapping' attribute is required.", parserContext.extractSource(element));
|
||||
return;
|
||||
String[] locations = StringUtils.commaDelimitedListToStringArray(element.getAttribute("location"));
|
||||
if (locations.length == 0) {
|
||||
parserContext.getReaderContext().error("The 'location' attribute is required.",
|
||||
parserContext.extractSource(element));
|
||||
return null;
|
||||
}
|
||||
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));
|
||||
MvcResources spec = new MvcResources(mapping, locations);
|
||||
if (element.hasAttribute("cache-period")) {
|
||||
spec.cachePeriod(element.getAttribute("cache-period"));
|
||||
}
|
||||
if (element.hasAttribute("order")) {
|
||||
spec.order(element.getAttribute("order"));
|
||||
}
|
||||
spec.source(parserContext.extractSource(element));
|
||||
spec.sourceName(element.getTagName());
|
||||
return spec;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
String beanName = parserContext.getReaderContext().generateBeanName(resourceHandlerDef);
|
||||
parserContext.getRegistry().registerBeanDefinition(beanName, resourceHandlerDef);
|
||||
parserContext.registerComponent(new BeanComponentDefinition(resourceHandlerDef, beanName));
|
||||
return beanName;
|
||||
/**
|
||||
* Adapt the given ParserContext instance into an ExecutorContext.
|
||||
*
|
||||
* TODO SPR-7420: consider unifying the two through a superinterface.
|
||||
* TODO SPR-7420: create a common ParserContext-to-ExecutorContext adapter util
|
||||
*/
|
||||
private ExecutorContext createExecutorContext(ParserContext parserContext) {
|
||||
ExecutorContext executorContext = new ExecutorContext();
|
||||
executorContext.setRegistry(parserContext.getRegistry());
|
||||
executorContext.setRegistrar(parserContext);
|
||||
executorContext.setProblemReporter(parserContext.getReaderContext().getProblemReporter());
|
||||
return executorContext;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,88 +16,49 @@
|
||||
|
||||
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.web.servlet.handler.SimpleUrlHandlerMapping;
|
||||
import org.springframework.context.config.ExecutorContext;
|
||||
import org.springframework.web.servlet.mvc.ParameterizableViewController;
|
||||
import org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* {@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 Keith Donald
|
||||
* @author Christian Dupuis
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.0
|
||||
* @see MvcViewControllers
|
||||
* @see MvcViewControllersExecutor
|
||||
*/
|
||||
class ViewControllerBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
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";
|
||||
|
||||
|
||||
/**
|
||||
* Parses the {@code <mvc:view-controller/>} tag.
|
||||
*/
|
||||
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<String, BeanDefinition> urlMap;
|
||||
if (handlerMappingDef.getPropertyValues().contains("urlMap")) {
|
||||
urlMap = (Map<String, BeanDefinition>) handlerMappingDef.getPropertyValues().getPropertyValue("urlMap").getValue();
|
||||
}
|
||||
else {
|
||||
urlMap = new ManagedMap<String, BeanDefinition>();
|
||||
handlerMappingDef.getPropertyValues().add("urlMap", urlMap);
|
||||
}
|
||||
urlMap.put(element.getAttribute("path"), viewControllerDef);
|
||||
String path = element.getAttribute("path");
|
||||
String viewName = element.getAttribute("view-name");
|
||||
new MvcViewControllers(path, viewName.isEmpty() ? null : viewName)
|
||||
.source(parserContext.extractSource(element))
|
||||
.sourceName(element.getTagName())
|
||||
.execute(createExecutorContext(parserContext));
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapt the given ParserContext instance into an ExecutorContext.
|
||||
*
|
||||
* TODO SPR-7420: consider unifying the two through a superinterface.
|
||||
* TODO SPR-7420: create a common ParserContext-to-ExecutorContext adapter util
|
||||
*/
|
||||
private ExecutorContext createExecutorContext(ParserContext parserContext) {
|
||||
ExecutorContext executorContext = new ExecutorContext();
|
||||
executorContext.setRegistry(parserContext.getRegistry());
|
||||
executorContext.setRegistrar(parserContext);
|
||||
executorContext.setProblemReporter(parserContext.getReaderContext().getProblemReporter());
|
||||
return executorContext;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user