Remove "Feature" support introduced in 3.1 M1

Feature-related support such as @Feature, @FeatureConfiguration,
and FeatureSpecification types will be replaced by framework-provided
@Configuration classes and convenience annotations such as
@ComponentScan (already exists), @EnableAsync, @EnableScheduling,
@EnableTransactionManagement and others.

Issue: SPR-8012,SPR-8034,SPR-8039,SPR-8188,SPR-8206,SPR-8223,
SPR-8225,SPR-8226,SPR-8227
This commit is contained in:
Chris Beams
2011-05-06 19:03:52 +00:00
parent 0a790c143f
commit 111fb71fe1
80 changed files with 857 additions and 6737 deletions

View File

@@ -0,0 +1,57 @@
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.servlet.config;
import org.w3c.dom.Element;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter;
/**
* Abstract base class for {@link BeanDefinitonParser}s that register an HttpRequestHandler.
*
* @author Jeremy Grelle
* @since 3.0.4
*/
abstract class AbstractHttpRequestHandlerBeanDefinitionParser implements BeanDefinitionParser{
private static final String HANDLER_ADAPTER_BEAN_NAME = "org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter";
public BeanDefinition parse(Element element, ParserContext parserContext) {
Object source = parserContext.extractSource(element);
registerHandlerAdapterIfNecessary(parserContext, source);
doParse(element, parserContext);
return null;
}
public abstract void doParse(Element element, ParserContext parserContext);
private void registerHandlerAdapterIfNecessary(ParserContext parserContext, Object source) {
if (!parserContext.getRegistry().containsBeanDefinition(HANDLER_ADAPTER_BEAN_NAME)) {
RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(HttpRequestHandlerAdapter.class);
handlerAdapterDef.setSource(source);
handlerAdapterDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
parserContext.getRegistry().registerBeanDefinition(HANDLER_ADAPTER_BEAN_NAME, handlerAdapterDef);
parserContext.registerComponent(new BeanComponentDefinition(handlerAdapterDef, HANDLER_ADAPTER_BEAN_NAME));
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,65 +16,265 @@
package org.springframework.web.servlet.config;
import java.util.ArrayList;
import java.util.List;
import org.w3c.dom.Element;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.context.config.AbstractSpecificationBeanDefinitionParser;
import org.springframework.context.config.FeatureSpecification;
import org.springframework.core.convert.ConversionService;
import org.springframework.format.support.FormattingConversionServiceFactoryBean;
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.ResourceHttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.feed.AtomFeedHttpMessageConverter;
import org.springframework.http.converter.feed.RssChannelHttpMessageConverter;
import org.springframework.http.converter.json.MappingJacksonHttpMessageConverter;
import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
import org.springframework.http.converter.xml.SourceHttpMessageConverter;
import org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter;
import org.springframework.util.ClassUtils;
import org.springframework.util.xml.DomUtils;
import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
import org.springframework.web.bind.support.WebArgumentResolver;
import org.springframework.web.servlet.handler.ConversionServiceExposingInterceptor;
import org.springframework.web.servlet.handler.MappedInterceptor;
import org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMethodAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMethodExceptionResolver;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMethodMapping;
import org.springframework.web.servlet.mvc.method.annotation.support.ServletWebArgumentResolverAdapter;
import org.w3c.dom.Element;
import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver;
/**
* {@link BeanDefinitionParser} that parses the {@code annotation-driven} element
* to configure a Spring MVC web application.
* {@link BeanDefinitionParser} that parses the {@code annotation-driven} element to configure a Spring MVC web
* application.
*
* <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
* @author Chris Beams
* @since 3.0
* @see MvcAnnotationDriven
* @see MvcAnnotationDrivenExecutor
*/
class AnnotationDrivenBeanDefinitionParser extends AbstractSpecificationBeanDefinitionParser {
class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
/**
* Parses the {@code <mvc:annotation-driven/>} tag.
*/
@Override
protected FeatureSpecification doParse(Element element, ParserContext parserContext) {
MvcAnnotationDriven spec = new MvcAnnotationDriven();
private static final boolean jsr303Present = ClassUtils.isPresent(
"javax.validation.Validator", AnnotationDrivenBeanDefinitionParser.class.getClassLoader());
private static final boolean jaxb2Present =
ClassUtils.isPresent("javax.xml.bind.Binder", AnnotationDrivenBeanDefinitionParser.class.getClassLoader());
private static final boolean jacksonPresent =
ClassUtils.isPresent("org.codehaus.jackson.map.ObjectMapper", AnnotationDrivenBeanDefinitionParser.class.getClassLoader()) &&
ClassUtils.isPresent("org.codehaus.jackson.JsonGenerator", AnnotationDrivenBeanDefinitionParser.class.getClassLoader());
private static boolean romePresent =
ClassUtils.isPresent("com.sun.syndication.feed.WireFeed", AnnotationDrivenBeanDefinitionParser.class.getClassLoader());
public BeanDefinition parse(Element element, ParserContext parserContext) {
Object source = parserContext.extractSource(element);
CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source);
parserContext.pushContainingComponent(compDefinition);
RootBeanDefinition methodMappingDef = new RootBeanDefinition(RequestMappingHandlerMethodMapping.class);
methodMappingDef.setSource(source);
methodMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
methodMappingDef.getPropertyValues().add("order", 0);
String methodMappingName = parserContext.getReaderContext().registerWithGeneratedName(methodMappingDef);
RuntimeBeanReference conversionService = getConversionService(element, source, parserContext);
RuntimeBeanReference validator = getValidator(element, source, parserContext);
RuntimeBeanReference messageCodesResolver = getMessageCodesResolver(element, source, parserContext);
RootBeanDefinition bindingDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class);
bindingDef.setSource(source);
bindingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
bindingDef.getPropertyValues().add("conversionService", conversionService);
bindingDef.getPropertyValues().add("validator", validator);
bindingDef.getPropertyValues().add("messageCodesResolver", messageCodesResolver);
ManagedList<?> messageConverters = getMessageConverters(element, source, parserContext);
ManagedList<?> argumentResolvers = getArgumentResolvers(element, source, parserContext);
RootBeanDefinition methodAdapterDef = new RootBeanDefinition(RequestMappingHandlerMethodAdapter.class);
methodAdapterDef.setSource(source);
methodAdapterDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
methodAdapterDef.getPropertyValues().add("webBindingInitializer", bindingDef);
methodAdapterDef.getPropertyValues().add("messageConverters", messageConverters);
if (argumentResolvers != null) {
methodAdapterDef.getPropertyValues().add("customArgumentResolvers", argumentResolvers);
}
String methodAdapterName = parserContext.getReaderContext().registerWithGeneratedName(methodAdapterDef);
RootBeanDefinition csInterceptorDef = new RootBeanDefinition(ConversionServiceExposingInterceptor.class);
csInterceptorDef.setSource(source);
csInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, conversionService);
RootBeanDefinition mappedCsInterceptorDef = new RootBeanDefinition(MappedInterceptor.class);
mappedCsInterceptorDef.setSource(source);
mappedCsInterceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
mappedCsInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, (Object) null);
mappedCsInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(1, csInterceptorDef);
String mappedInterceptorName = parserContext.getReaderContext().registerWithGeneratedName(mappedCsInterceptorDef);
RootBeanDefinition methodExceptionResolver = new RootBeanDefinition(RequestMappingHandlerMethodExceptionResolver.class);
methodExceptionResolver.setSource(source);
methodExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
methodExceptionResolver.getPropertyValues().add("messageConverters", messageConverters);
methodExceptionResolver.getPropertyValues().add("order", 0);
String methodExceptionResolverName =
parserContext.getReaderContext().registerWithGeneratedName(methodExceptionResolver);
RootBeanDefinition responseStatusExceptionResolver = new RootBeanDefinition(ResponseStatusExceptionResolver.class);
responseStatusExceptionResolver.setSource(source);
responseStatusExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
responseStatusExceptionResolver.getPropertyValues().add("order", 1);
String responseStatusExceptionResolverName =
parserContext.getReaderContext().registerWithGeneratedName(responseStatusExceptionResolver);
RootBeanDefinition defaultExceptionResolver = new RootBeanDefinition(DefaultHandlerExceptionResolver.class);
defaultExceptionResolver.setSource(source);
defaultExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
defaultExceptionResolver.getPropertyValues().add("order", 2);
String defaultExceptionResolverName =
parserContext.getReaderContext().registerWithGeneratedName(defaultExceptionResolver);
parserContext.registerComponent(new BeanComponentDefinition(methodMappingDef, methodMappingName));
parserContext.registerComponent(new BeanComponentDefinition(methodAdapterDef, methodAdapterName));
parserContext.registerComponent(new BeanComponentDefinition(methodExceptionResolver, methodExceptionResolverName));
parserContext.registerComponent(new BeanComponentDefinition(responseStatusExceptionResolver, responseStatusExceptionResolverName));
parserContext.registerComponent(new BeanComponentDefinition(defaultExceptionResolver, defaultExceptionResolverName));
parserContext.registerComponent(new BeanComponentDefinition(mappedCsInterceptorDef, mappedInterceptorName));
parserContext.popAndRegisterContainingComponent();
return null;
}
private RuntimeBeanReference getConversionService(Element element, Object source, ParserContext parserContext) {
RuntimeBeanReference conversionServiceRef;
if (element.hasAttribute("conversion-service")) {
String conversionService = element.getAttribute("conversion-service");
spec.conversionService(conversionService);
conversionServiceRef = new RuntimeBeanReference(element.getAttribute("conversion-service"));
}
else {
RootBeanDefinition conversionDef = new RootBeanDefinition(FormattingConversionServiceFactoryBean.class);
conversionDef.setSource(source);
conversionDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
String conversionName = parserContext.getReaderContext().registerWithGeneratedName(conversionDef);
parserContext.registerComponent(new BeanComponentDefinition(conversionDef, conversionName));
conversionServiceRef = new RuntimeBeanReference(conversionName);
}
return conversionServiceRef;
}
private RuntimeBeanReference getValidator(Element element, Object source, ParserContext parserContext) {
if (element.hasAttribute("validator")) {
spec.validator(element.getAttribute("validator"));
return new RuntimeBeanReference(element.getAttribute("validator"));
}
else if (jsr303Present) {
RootBeanDefinition validatorDef = new RootBeanDefinition(LocalValidatorFactoryBean.class);
validatorDef.setSource(source);
validatorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
String validatorName = parserContext.getReaderContext().registerWithGeneratedName(validatorDef);
parserContext.registerComponent(new BeanComponentDefinition(validatorDef, validatorName));
return new RuntimeBeanReference(validatorName);
}
else {
return null;
}
}
private RuntimeBeanReference getMessageCodesResolver(Element element, Object source, ParserContext parserContext) {
if (element.hasAttribute("message-codes-resolver")) {
spec.messageCodesResolver(element.getAttribute("message-codes-resolver"));
}
Element convertersElement = DomUtils.getChildElementByTagName(element, "message-converters");
if (convertersElement != null) {
if (convertersElement.hasAttribute("register-defaults")) {
spec.shouldRegisterDefaultMessageConverters(Boolean.valueOf(convertersElement
.getAttribute("register-defaults")));
}
spec.messageConverters(extractBeanSubElements(convertersElement, parserContext));
return new RuntimeBeanReference(element.getAttribute("message-codes-resolver"));
} else {
return null;
}
}
private ManagedList<?> getArgumentResolvers(Element element, Object source, ParserContext parserContext) {
Element resolversElement = DomUtils.getChildElementByTagName(element, "argument-resolvers");
if (resolversElement != null) {
ManagedList<BeanDefinitionHolder> beanDefs = extractBeanSubElements(resolversElement, parserContext);
spec.argumentResolvers(wrapWebArgumentResolverBeanDefs(beanDefs));
ManagedList<BeanDefinitionHolder> argumentResolvers = extractBeanSubElements(resolversElement, parserContext);
return wrapWebArgumentResolverBeanDefs(argumentResolvers);
}
return null;
}
private ManagedList<?> getMessageConverters(Element element, Object source, ParserContext parserContext) {
Element convertersElement = DomUtils.getChildElementByTagName(element, "message-converters");
ManagedList<? super Object> messageConverters = new ManagedList<Object>();
if (convertersElement != null) {
messageConverters.setSource(source);
for (Element converter : DomUtils.getChildElementsByTagName(convertersElement, "bean")) {
BeanDefinitionHolder beanDef = parserContext.getDelegate().parseBeanDefinitionElement(converter);
beanDef = parserContext.getDelegate().decorateBeanDefinitionIfRequired(converter, beanDef);
messageConverters.add(beanDef);
}
}
return spec;
if (convertersElement == null || Boolean.valueOf(convertersElement.getAttribute("register-defaults"))) {
messageConverters.setSource(source);
messageConverters.add(createConverterBeanDefinition(ByteArrayHttpMessageConverter.class, source));
RootBeanDefinition stringConverterDef = createConverterBeanDefinition(StringHttpMessageConverter.class,
source);
stringConverterDef.getPropertyValues().add("writeAcceptCharset", false);
messageConverters.add(stringConverterDef);
messageConverters.add(createConverterBeanDefinition(ResourceHttpMessageConverter.class, source));
messageConverters.add(createConverterBeanDefinition(SourceHttpMessageConverter.class, source));
messageConverters.add(createConverterBeanDefinition(XmlAwareFormHttpMessageConverter.class, source));
if (jaxb2Present) {
messageConverters
.add(createConverterBeanDefinition(Jaxb2RootElementHttpMessageConverter.class, source));
}
if (jacksonPresent) {
messageConverters.add(createConverterBeanDefinition(MappingJacksonHttpMessageConverter.class, source));
}
if (romePresent) {
messageConverters.add(createConverterBeanDefinition(AtomFeedHttpMessageConverter.class, source));
messageConverters.add(createConverterBeanDefinition(RssChannelHttpMessageConverter.class, source));
}
}
return messageConverters;
}
private RootBeanDefinition createConverterBeanDefinition(Class<? extends HttpMessageConverter> converterClass,
Object source) {
RootBeanDefinition beanDefinition = new RootBeanDefinition(converterClass);
beanDefinition.setSource(source);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
return beanDefinition;
}
private ManagedList<BeanDefinitionHolder> extractBeanSubElements(Element parentElement, ParserContext parserContext) {
@@ -90,21 +290,20 @@ class AnnotationDrivenBeanDefinitionParser extends AbstractSpecificationBeanDefi
private ManagedList<BeanDefinitionHolder> wrapWebArgumentResolverBeanDefs(List<BeanDefinitionHolder> beanDefs) {
ManagedList<BeanDefinitionHolder> result = new ManagedList<BeanDefinitionHolder>();
for (BeanDefinitionHolder beanDef : beanDefs) {
String className = beanDef.getBeanDefinition().getBeanClassName();
Class<?> clazz = ClassUtils.resolveClassName(className, ClassUtils.getDefaultClassLoader());
if (WebArgumentResolver.class.isAssignableFrom(clazz)) {
RootBeanDefinition adapter = new RootBeanDefinition(ServletWebArgumentResolverAdapter.class);
adapter.getConstructorArgumentValues().addIndexedArgumentValue(0, beanDef);
result.add(new BeanDefinitionHolder(adapter, beanDef.getBeanName() + "Adapter"));
}
else {
} else {
result.add(beanDef);
}
}
return result;
}
}

View File

@@ -16,36 +16,58 @@
package org.springframework.web.servlet.config;
import java.util.Map;
import org.w3c.dom.Element;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.context.config.AbstractSpecificationBeanDefinitionParser;
import org.springframework.context.config.FeatureSpecification;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter;
import org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler;
import org.w3c.dom.Element;
/**
* {@link BeanDefinitionParser} that parses a {@code default-servlet-handler} element to
* register a {@link DefaultServletHttpRequestHandler}. Will also register a
* {@link SimpleUrlHandlerMapping} for mapping resource requests, and a
* {@link HttpRequestHandlerAdapter} if necessary.
*
* @author Rossen Stoyanchev
* @author Chris Beams
*
* @author Jeremy Grelle
* @since 3.0.4
*/
class DefaultServletHandlerBeanDefinitionParser extends AbstractSpecificationBeanDefinitionParser {
class DefaultServletHandlerBeanDefinitionParser extends AbstractHttpRequestHandlerBeanDefinitionParser {
/**
* Parses the {@code <mvc:default-servlet-handler/>} tag.
*/
public FeatureSpecification doParse(Element element, ParserContext parserContext) {
String defaultServletHandler = element.getAttribute("default-servlet-handler");
return StringUtils.hasText(defaultServletHandler) ?
new MvcDefaultServletHandler(defaultServletHandler) :
new MvcDefaultServletHandler();
@Override
public void doParse(Element element, ParserContext parserContext) {
Object source = parserContext.extractSource(element);
String defaultServletName = element.getAttribute("default-servlet-name");
RootBeanDefinition defaultServletHandlerDef = new RootBeanDefinition(DefaultServletHttpRequestHandler.class);
defaultServletHandlerDef.setSource(source);
defaultServletHandlerDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
if (StringUtils.hasText(defaultServletName)) {
defaultServletHandlerDef.getPropertyValues().add("defaultServletName", defaultServletName);
}
String defaultServletHandlerName = parserContext.getReaderContext().generateBeanName(defaultServletHandlerDef);
parserContext.getRegistry().registerBeanDefinition(defaultServletHandlerName, defaultServletHandlerDef);
parserContext.registerComponent(new BeanComponentDefinition(defaultServletHandlerDef, defaultServletHandlerName));
Map<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));
}
}

View File

@@ -18,54 +18,59 @@ package org.springframework.web.servlet.config;
import java.util.List;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.context.config.AbstractSpecificationBeanDefinitionParser;
import org.springframework.context.config.FeatureSpecification;
import org.springframework.util.xml.DomUtils;
import org.springframework.web.servlet.handler.MappedInterceptor;
import org.w3c.dom.Element;
/**
* {@link org.springframework.beans.factory.xml.BeanDefinitionParser} that parses
* a {@code interceptors} element to register set of {@link MappedInterceptor}
* definitions.
* {@link org.springframework.beans.factory.xml.BeanDefinitionParser} that parses a {@code interceptors} element to register
* a set of {@link MappedInterceptor} definitions.
*
* @author Keith Donald
* @author Rossen Stoyanchev
*
* @since 3.0
*/
class InterceptorsBeanDefinitionParser extends AbstractSpecificationBeanDefinitionParser {
/**
* Parses the {@code <mvc:interceptors/>} tag.
*/
public FeatureSpecification doParse(Element element, ParserContext parserContext) {
MvcInterceptors mvcInterceptors = new MvcInterceptors();
class InterceptorsBeanDefinitionParser implements BeanDefinitionParser {
public BeanDefinition parse(Element element, ParserContext parserContext) {
CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
parserContext.pushContainingComponent(compDefinition);
List<Element> interceptors = DomUtils.getChildElementsByTagName(element, new String[] { "bean", "interceptor" });
for (Element interceptor : interceptors) {
RootBeanDefinition mappedInterceptorDef = new RootBeanDefinition(MappedInterceptor.class);
mappedInterceptorDef.setSource(parserContext.extractSource(interceptor));
mappedInterceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
String[] pathPatterns;
BeanDefinitionHolder interceptorDef;
if ("interceptor".equals(interceptor.getLocalName())) {
List<Element> paths = DomUtils.getChildElementsByTagName(interceptor, "mapping");
String[] pathPatterns = new String[paths.size()];
pathPatterns = new String[paths.size()];
for (int i = 0; i < paths.size(); i++) {
pathPatterns[i] = paths.get(i).getAttribute("path");
}
Element beanElement = DomUtils.getChildElementByTagName(interceptor, "bean");
mvcInterceptors.interceptor(pathPatterns, parseBeanElement(parserContext, beanElement));
Element interceptorBean = DomUtils.getChildElementByTagName(interceptor, "bean");
interceptorDef = parserContext.getDelegate().parseBeanDefinitionElement(interceptorBean);
interceptorDef = parserContext.getDelegate().decorateBeanDefinitionIfRequired(interceptorBean, interceptorDef);
} else {
mvcInterceptors.interceptor(null, parseBeanElement(parserContext, interceptor));
pathPatterns = null;
interceptorDef = parserContext.getDelegate().parseBeanDefinitionElement(interceptor);
interceptorDef = parserContext.getDelegate().decorateBeanDefinitionIfRequired(interceptor, interceptorDef);
}
mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, pathPatterns);
mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(1, interceptorDef);
String mappedInterceptorName = parserContext.getReaderContext().registerWithGeneratedName(mappedInterceptorDef);
parserContext.registerComponent(new BeanComponentDefinition(mappedInterceptorDef, mappedInterceptorName));
}
return mvcInterceptors;
parserContext.popAndRegisterContainingComponent();
return null;
}
private BeanDefinitionHolder parseBeanElement(ParserContext parserContext, Element interceptor) {
BeanDefinitionHolder beanDef = parserContext.getDelegate().parseBeanDefinitionElement(interceptor);
beanDef = parserContext.getDelegate().decorateBeanDefinitionIfRequired(interceptor, beanDef);
return beanDef;
}
}

View File

@@ -1,259 +0,0 @@
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.servlet.config;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.parsing.ProblemCollector;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.context.config.AbstractFeatureSpecification;
import org.springframework.context.config.FeatureSpecificationExecutor;
import org.springframework.core.convert.ConversionService;
import org.springframework.format.support.FormattingConversionServiceFactoryBean;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.feed.AtomFeedHttpMessageConverter;
import org.springframework.http.converter.feed.RssChannelHttpMessageConverter;
import org.springframework.http.converter.json.MappingJacksonHttpMessageConverter;
import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
import org.springframework.validation.MessageCodesResolver;
import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.bind.support.WebArgumentResolver;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.mvc.method.annotation.support.ServletWebArgumentResolverAdapter;
/**
* Specifies the Spring MVC "annotation-driven" container feature. The
* feature provides the following fine-grained configuration:
*
* <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<BeanDefinitionHolder> converterBeanDefinitions) {
this.messageConverters.addAll(converterBeanDefinitions);
}
ManagedList<?> messageConverters() {
return this.messageConverters;
}
/**
* Indicates whether or not default HttpMessageConverter registrations should
* be added in addition to the ones provided via
* {@link #messageConverters(HttpMessageConverter...)}
*
* @param shouldRegister true will result in registration of defaults.
*/
public MvcAnnotationDriven shouldRegisterDefaultMessageConverters(boolean shouldRegister) {
this.shouldRegisterDefaultMessageConverters = shouldRegister;
return this;
}
boolean shouldRegisterDefaultMessageConverters() {
return this.shouldRegisterDefaultMessageConverters;
}
public MvcAnnotationDriven argumentResolvers(HandlerMethodArgumentResolver... resolvers) {
for (HandlerMethodArgumentResolver resolver : resolvers) {
this.argumentResolvers.add(resolver);
}
return this;
}
public MvcAnnotationDriven argumentResolvers(WebArgumentResolver... resolvers) {
for (WebArgumentResolver resolver : resolvers) {
this.argumentResolvers.add(new ServletWebArgumentResolverAdapter(resolver));
}
return this;
}
void argumentResolvers(ManagedList<BeanDefinitionHolder> resolverBeanDefinitions) {
this.argumentResolvers.addAll(resolverBeanDefinitions);
}
ManagedList<?> argumentResolvers() {
return this.argumentResolvers;
}
/**
* The Validator bean instance to use to validate Controller model objects.
* This is not required input. It only needs to be specified explicitly if
* a custom Validator needs to be configured.
*
* <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(ProblemCollector problems) {
}
}

View File

@@ -1,236 +0,0 @@
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.servlet.config;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.parsing.ComponentRegistrar;
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.config.AbstractSpecificationExecutor;
import org.springframework.context.config.SpecificationContext;
import org.springframework.format.support.FormattingConversionServiceFactoryBean;
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.ResourceHttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.feed.AtomFeedHttpMessageConverter;
import org.springframework.http.converter.feed.RssChannelHttpMessageConverter;
import org.springframework.http.converter.json.MappingJacksonHttpMessageConverter;
import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
import org.springframework.http.converter.xml.SourceHttpMessageConverter;
import org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter;
import org.springframework.util.ClassUtils;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
import org.springframework.web.servlet.handler.ConversionServiceExposingInterceptor;
import org.springframework.web.servlet.handler.MappedInterceptor;
import org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMethodAdapter;
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMethodMapping;
import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver;
/**
* Executes {@link MvcAnnotationDriven} specifications, creating and registering
* bean definitions as appropriate based on the configuration within.
*
* @author Keith Donald
* @author Juergen Hoeller
* @author Arjen Poutsma
* @author Rossen Stoyanchev
* @since 3.1
* @see MvcAnnotationDriven
*/
final class MvcAnnotationDrivenExecutor extends AbstractSpecificationExecutor<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, SpecificationContext specContext) {
ComponentRegistrar registrar = specContext.getRegistrar();
Object source = spec.source();
RootBeanDefinition methodMappingDef = new RootBeanDefinition(RequestMappingHandlerMethodMapping.class);
methodMappingDef.setSource(source);
methodMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
methodMappingDef.getPropertyValues().add("order", 0);
String methodMappingName = registrar.registerWithGeneratedName(methodMappingDef);
Object conversionService = getConversionService(spec, registrar);
Object validator = getValidator(spec, registrar);
Object messageCodesResolver = getMessageCodesResolver(spec, registrar);
RootBeanDefinition bindingDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class);
bindingDef.setSource(source);
bindingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
bindingDef.getPropertyValues().add("conversionService", conversionService);
bindingDef.getPropertyValues().add("validator", validator);
bindingDef.getPropertyValues().add("messageCodesResolver", messageCodesResolver);
ManagedList<? super Object> messageConverters = getMessageConverters(spec, registrar);
RootBeanDefinition methodAdapterDef = new RootBeanDefinition(RequestMappingHandlerMethodAdapter.class);
methodAdapterDef.setSource(source);
methodAdapterDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
methodAdapterDef.getPropertyValues().add("webBindingInitializer", bindingDef);
methodAdapterDef.getPropertyValues().add("messageConverters", messageConverters);
if (!spec.argumentResolvers().isEmpty()) {
methodAdapterDef.getPropertyValues().add("customArgumentResolvers", spec.argumentResolvers());
}
String methodAdapterName = registrar.registerWithGeneratedName(methodAdapterDef);
RootBeanDefinition csInterceptorDef = new RootBeanDefinition(ConversionServiceExposingInterceptor.class);
csInterceptorDef.setSource(source);
csInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, conversionService);
RootBeanDefinition mappedCsInterceptorDef = new RootBeanDefinition(MappedInterceptor.class);
mappedCsInterceptorDef.setSource(source);
mappedCsInterceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
mappedCsInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, (Object) null);
mappedCsInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(1, csInterceptorDef);
String mappedInterceptorName = registrar.registerWithGeneratedName(mappedCsInterceptorDef);
RootBeanDefinition methodExceptionResolver = new RootBeanDefinition(
ExceptionHandlerExceptionResolver.class);
methodExceptionResolver.setSource(source);
methodExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
methodExceptionResolver.getPropertyValues().add("messageConverters", messageConverters);
methodExceptionResolver.getPropertyValues().add("order", 0);
String methodExceptionResolverName = registrar.registerWithGeneratedName(methodExceptionResolver);
RootBeanDefinition responseStatusExceptionResolver = new RootBeanDefinition(
ResponseStatusExceptionResolver.class);
responseStatusExceptionResolver.setSource(source);
responseStatusExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
responseStatusExceptionResolver.getPropertyValues().add("order", 1);
String responseStatusExceptionResolverName = registrar
.registerWithGeneratedName(responseStatusExceptionResolver);
RootBeanDefinition defaultExceptionResolver = new RootBeanDefinition(DefaultHandlerExceptionResolver.class);
defaultExceptionResolver.setSource(source);
defaultExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
defaultExceptionResolver.getPropertyValues().add("order", 2);
String defaultExceptionResolverName = registrar.registerWithGeneratedName(defaultExceptionResolver);
CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(spec.sourceName(), source);
compDefinition.addNestedComponent(new BeanComponentDefinition(methodMappingDef, methodMappingName));
compDefinition.addNestedComponent(new BeanComponentDefinition(methodAdapterDef, methodAdapterName));
compDefinition.addNestedComponent(new BeanComponentDefinition(methodExceptionResolver, methodExceptionResolverName));
compDefinition.addNestedComponent(new BeanComponentDefinition(responseStatusExceptionResolver,
responseStatusExceptionResolverName));
compDefinition.addNestedComponent(new BeanComponentDefinition(defaultExceptionResolver,
defaultExceptionResolverName));
compDefinition.addNestedComponent(new BeanComponentDefinition(mappedCsInterceptorDef, mappedInterceptorName));
registrar.registerComponent(compDefinition);
}
private Object getConversionService(MvcAnnotationDriven spec, ComponentRegistrar registrar) {
if (spec.conversionService() != null) {
return getBeanOrReference(spec.conversionService());
} else {
RootBeanDefinition conversionDef = new RootBeanDefinition(FormattingConversionServiceFactoryBean.class);
conversionDef.setSource(spec.source());
conversionDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
String conversionName = registrar.registerWithGeneratedName(conversionDef);
registrar.registerComponent(new BeanComponentDefinition(conversionDef, conversionName));
return new RuntimeBeanReference(conversionName);
}
}
private Object getValidator(MvcAnnotationDriven spec, ComponentRegistrar registrar) {
if (spec.validator() != null) {
return getBeanOrReference(spec.validator());
} else if (jsr303Present) {
RootBeanDefinition validatorDef = new RootBeanDefinition(LocalValidatorFactoryBean.class);
validatorDef.setSource(spec.source());
validatorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
String validatorName = registrar.registerWithGeneratedName(validatorDef);
registrar.registerComponent(new BeanComponentDefinition(validatorDef, validatorName));
return new RuntimeBeanReference(validatorName);
} else {
return null;
}
}
private Object getMessageCodesResolver(MvcAnnotationDriven spec, ComponentRegistrar registrar) {
if (spec.messageCodesResolver() != null) {
return getBeanOrReference(spec.messageCodesResolver());
} else {
return null;
}
}
private ManagedList<? 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;
}
}
}

View File

@@ -1,91 +0,0 @@
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.servlet.config;
import org.springframework.beans.factory.parsing.ProblemCollector;
import org.springframework.context.config.AbstractFeatureSpecification;
import org.springframework.context.config.FeatureSpecificationExecutor;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter;
import org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler;
/**
* Specifies the Spring MVC "default-servlet-handler" container feature. The
* feature provides the following fine-grained configuration:
*
* <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>
*
* This handler will forward all requests to the default Servlet. Therefore
* it is important that it remains last in the order of all other URL
* HandlerMappings. That will be the case if you use the {@link MvcAnnotationDriven}
* feature or alternatively if you are setting up your customized HandlerMapping
* instance be sure to set its "order" property to a value lower than that of
* the DefaultServletHttpRequestHandler, which is Integer.MAX_VALUE.
*
* @author Rossen Stoyanchev
* @since 3.1
*/
public final class MvcDefaultServletHandler extends AbstractFeatureSpecification {
private static final Class<? 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(ProblemCollector problems) {
}
}

View File

@@ -1,82 +0,0 @@
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.servlet.config;
import java.util.Map;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.parsing.ComponentRegistrar;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.config.AbstractSpecificationExecutor;
import org.springframework.context.config.SpecificationContext;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter;
import org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler;
/**
* Executes {@link MvcDefaultServletHandler} specifications, creating and
* registering bean definitions as appropriate based on the configuration
* within.
*
* @author Jeremy Grelle
* @author Rossen Stoyanchev
* @since 3.1
*/
final class MvcDefaultServletHandlerExecutor extends AbstractSpecificationExecutor<MvcDefaultServletHandler> {
private static final String HANDLER_ADAPTER_BEAN_NAME = "org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter";
@Override
protected void doExecute(MvcDefaultServletHandler spec, SpecificationContext specContext) {
BeanDefinitionRegistry registry = specContext.getRegistry();
ComponentRegistrar registrar = specContext.getRegistrar();
Object source = spec.source();
if (!registry.containsBeanDefinition(HANDLER_ADAPTER_BEAN_NAME)) {
RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(HttpRequestHandlerAdapter.class);
handlerAdapterDef.setSource(source);
handlerAdapterDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(HANDLER_ADAPTER_BEAN_NAME, handlerAdapterDef);
registrar.registerComponent(new BeanComponentDefinition(handlerAdapterDef, HANDLER_ADAPTER_BEAN_NAME));
}
RootBeanDefinition defaultServletHandlerDef = new RootBeanDefinition(DefaultServletHttpRequestHandler.class);
defaultServletHandlerDef.setSource(source);
defaultServletHandlerDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
if (StringUtils.hasText(spec.defaultServletName())) {
defaultServletHandlerDef.getPropertyValues().add("defaultServletName", spec.defaultServletName());
}
String defaultServletHandlerName = registrar.registerWithGeneratedName(defaultServletHandlerDef);
registry.registerBeanDefinition(defaultServletHandlerName, defaultServletHandlerDef);
registrar.registerComponent(new BeanComponentDefinition(defaultServletHandlerDef, defaultServletHandlerName));
Map<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));
}
}

View File

@@ -1,158 +0,0 @@
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.servlet.config;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.parsing.ProblemCollector;
import org.springframework.context.config.AbstractFeatureSpecification;
import org.springframework.context.config.FeatureSpecificationExecutor;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.WebRequestInterceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.handler.MappedInterceptor;
/**
* Specifies the Spring MVC "interceptors" container feature. The feature
* registers one or more {@link MappedInterceptor} bean definitions. A
* MappedInterceptor encapsulates an interceptor and one or more (optional)
* path patterns to which the interceptor is mapped. The interceptor can be
* of type {@link HandlerInterceptor} or {@link WebRequestInterceptor}.
* An interceptor can also be provided without path patterns in which case
* it applies globally to all handler invocations.
*
* @author Rossen Stoyanchev
* @since 3.1
*/
public class MvcInterceptors extends AbstractFeatureSpecification {
private static final Class<? extends FeatureSpecificationExecutor> EXECUTOR_TYPE = MvcInterceptorsExecutor.class;
private Map<Object, String[]> interceptorMappings = new LinkedHashMap<Object, String[]>();
/**
* Creates an MvcInterceptors instance.
*/
public MvcInterceptors() {
super(EXECUTOR_TYPE);
}
/**
* Add one or more {@link HandlerInterceptor HandlerInterceptors} that should
* intercept all handler invocations.
*
* @param interceptors one or more interceptors
*/
public MvcInterceptors globalInterceptors(HandlerInterceptor... interceptors) {
addInterceptorMappings(null, interceptors);
return this;
}
/**
* Add one or more {@link WebRequestInterceptor WebRequestInterceptors} that should
* intercept all handler invocations.
*
* @param interceptors one or more interceptors
*/
public MvcInterceptors globalInterceptors(WebRequestInterceptor... interceptors) {
addInterceptorMappings(null, interceptors);
return this;
}
/**
* Add one or more interceptors by bean name that should intercept all handler
* invocations.
*
* @param interceptors interceptor bean names
*/
public MvcInterceptors globalInterceptors(String... interceptors) {
addInterceptorMappings(null, interceptors);
return this;
}
/**
* Add one or more {@link HandlerInterceptor HandlerInterceptors} and map
* them to the specified path patterns.
*
* @param pathPatterns the pathPatterns to map the interceptor to
* @param interceptors the interceptors
*/
public MvcInterceptors mappedInterceptors(String[] pathPatterns, HandlerInterceptor... interceptors) {
addInterceptorMappings(pathPatterns, interceptors);
return this;
}
/**
* Add one or more {@link WebRequestInterceptor WebRequestInterceptors} and
* map them to the specified path patterns.
*
* @param pathPatterns the pathPatterns to map the interceptor to
* @param interceptors the interceptors
*/
public MvcInterceptors mappedInterceptors(String[] pathPatterns, WebRequestInterceptor... interceptors) {
addInterceptorMappings(pathPatterns, interceptors);
return this;
}
/**
* Add one or more interceptors by bean name and map them to the specified
* path patterns.
*
* @param pathPatterns the pathPatterns to map to
* @param interceptors the interceptors
*/
public MvcInterceptors mappedInterceptors(String[] pathPatterns, String... interceptors) {
addInterceptorMappings(pathPatterns, interceptors);
return this;
}
void interceptor(String[] pathPatterns, BeanDefinitionHolder interceptor) {
addInterceptorMappings(pathPatterns, new Object[] { interceptor });
}
Map<Object, String[]> interceptorMappings() {
return Collections.unmodifiableMap(interceptorMappings);
}
private void addInterceptorMappings(String[] pathPatterns, Object[] interceptors) {
for (Object interceptor : interceptors) {
interceptorMappings.put(interceptor, pathPatterns);
}
}
@Override
protected void doValidate(ProblemCollector problems) {
if (interceptorMappings.size() == 0) {
problems.error("No interceptors defined.");
}
for (Object interceptor : interceptorMappings.keySet()) {
if (interceptor == null) {
problems.error("Null interceptor provided.");
}
if (interceptorMappings.get(interceptor) != null) {
for (String pattern : interceptorMappings.get(interceptor)) {
if (!StringUtils.hasText(pattern)) {
problems.error("Empty path pattern specified for " + interceptor);
}
}
}
}
}
}

View File

@@ -1,60 +0,0 @@
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.servlet.config;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.parsing.ComponentRegistrar;
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.config.AbstractSpecificationExecutor;
import org.springframework.context.config.SpecificationContext;
import org.springframework.web.servlet.handler.MappedInterceptor;
/**
* Executes {@link MvcInterceptors} specification, creating and registering
* bean definitions as appropriate based on the configuration within.
*
* @author Keith Donald
* @author Rossen Stoyanchev
*
* @since 3.1
*/
final class MvcInterceptorsExecutor extends AbstractSpecificationExecutor<MvcInterceptors> {
@Override
protected void doExecute(MvcInterceptors spec, SpecificationContext specContext) {
ComponentRegistrar registrar = specContext.getRegistrar();
Object source = spec.source();
CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(spec.sourceName(), source);
for (Object interceptor : spec.interceptorMappings().keySet()) {
RootBeanDefinition beanDef = new RootBeanDefinition(MappedInterceptor.class);
beanDef.setSource(source);
beanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
beanDef.getConstructorArgumentValues().addIndexedArgumentValue(0,
spec.interceptorMappings().get(interceptor));
beanDef.getConstructorArgumentValues().addIndexedArgumentValue(1, interceptor);
String beanName = registrar.registerWithGeneratedName(beanDef);
compDefinition.addNestedComponent(new BeanComponentDefinition(beanDef, beanName));
}
registrar.registerComponent(compDefinition);
}
}

View File

@@ -1,179 +0,0 @@
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.servlet.config;
import org.springframework.beans.factory.parsing.ProblemCollector;
import org.springframework.context.config.AbstractFeatureSpecification;
import org.springframework.context.config.FeatureSpecificationExecutor;
import org.springframework.core.Ordered;
import org.springframework.core.io.Resource;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter;
import org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping;
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
/**
* Specifies the Spring MVC "resources" container feature. The
* feature provides the following fine-grained configuration:
*
* <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(ProblemCollector problems) {
if (!StringUtils.hasText(mapping)) {
problems.error("Mapping is required");
}
if (locations == null || locations.length == 0) {
problems.error("At least one location is required");
}
}
}

View File

@@ -1,85 +0,0 @@
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.servlet.config;
import java.util.Map;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.parsing.ComponentRegistrar;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.config.AbstractSpecificationExecutor;
import org.springframework.context.config.SpecificationContext;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter;
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
/**
* Executes {@link MvcResources} specifications, creating and registering
* bean definitions as appropriate based on the configuration within.
*
* @author Keith Donald
* @author Jeremy Grelle
* @author Rossen Stoyanchev
* @since 3.1
*/
final class MvcResourcesExecutor extends AbstractSpecificationExecutor<MvcResources> {
private static final String HANDLER_ADAPTER_BEAN_NAME = "org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter";
@Override
protected void doExecute(MvcResources spec, SpecificationContext specContext) {
BeanDefinitionRegistry registry = specContext.getRegistry();
ComponentRegistrar registrar = specContext.getRegistrar();
Object source = spec.source();
if (!registry.containsBeanDefinition(HANDLER_ADAPTER_BEAN_NAME)) {
RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(HttpRequestHandlerAdapter.class);
handlerAdapterDef.setSource(source);
handlerAdapterDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(HANDLER_ADAPTER_BEAN_NAME, handlerAdapterDef);
registrar.registerComponent(new BeanComponentDefinition(handlerAdapterDef, HANDLER_ADAPTER_BEAN_NAME));
}
RootBeanDefinition resourceHandlerDef = new RootBeanDefinition(ResourceHttpRequestHandler.class);
resourceHandlerDef.setSource(source);
resourceHandlerDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
resourceHandlerDef.getPropertyValues().add("locations", spec.locations());
if (spec.cachePeriod() != null) {
resourceHandlerDef.getPropertyValues().add("cacheSeconds", spec.cachePeriod());
}
String resourceHandlerBeanName = registrar.registerWithGeneratedName(resourceHandlerDef);
registry.registerBeanDefinition(resourceHandlerBeanName, resourceHandlerDef);
registrar.registerComponent(new BeanComponentDefinition(resourceHandlerDef, resourceHandlerBeanName));
Map<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));
}
}

View File

@@ -1,90 +0,0 @@
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.servlet.config;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.parsing.ProblemCollector;
import org.springframework.context.config.AbstractFeatureSpecification;
import org.springframework.context.config.FeatureSpecificationExecutor;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
import org.springframework.web.servlet.mvc.ParameterizableViewController;
import org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter;
/**
* Specifies the Spring MVC "View Controllers" container feature. The
* feature allows specifying one or more path to view name mappings.
* It sets up the following fine-grained configuration:
*
* <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(ProblemCollector problems) {
if (mappings.size() == 0) {
problems.error("At least one ViewController must be defined");
}
for (String path : mappings.keySet()) {
if (!StringUtils.hasText(path)) {
problems.error("The path attribute in a ViewController is required");
}
String viewName = mappings.get(path);
if (viewName != null && viewName.isEmpty()) {
problems.error("The view name in a ViewController may be null but not empty.");
}
}
}
}

View File

@@ -1,89 +0,0 @@
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/package org.springframework.web.servlet.config;
import java.util.Map;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.parsing.ComponentRegistrar;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.config.AbstractSpecificationExecutor;
import org.springframework.context.config.SpecificationContext;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
import org.springframework.web.servlet.mvc.ParameterizableViewController;
import org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter;
/**
* Executes {@link MvcViewControllers} specification, creating and registering
* bean definitions as appropriate based on the configuration within.
*
* @author Keith Donald
* @author Christian Dupuis
* @author Rossen Stoyanchev
* @since 3.1
*/
final class MvcViewControllersExecutor extends AbstractSpecificationExecutor<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, SpecificationContext specContext) {
BeanDefinitionRegistry registry = specContext.getRegistry();
ComponentRegistrar registrar = specContext.getRegistrar();
Object source = spec.source();
if (!registry.containsBeanDefinition(HANDLER_ADAPTER_BEAN_NAME)) {
RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(SimpleControllerHandlerAdapter.class);
handlerAdapterDef.setSource(source);
handlerAdapterDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(HANDLER_ADAPTER_BEAN_NAME, handlerAdapterDef);
registrar.registerComponent(new BeanComponentDefinition(handlerAdapterDef, HANDLER_ADAPTER_BEAN_NAME));
}
BeanDefinition handlerMappingBeanDef = null;
if (!registry.containsBeanDefinition(HANDLER_MAPPING_BEAN_NAME)) {
RootBeanDefinition beanDef = new RootBeanDefinition(SimpleUrlHandlerMapping.class);
beanDef.setSource(source);
beanDef.getPropertyValues().add("order", "1");
beanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(HANDLER_MAPPING_BEAN_NAME, beanDef);
registrar.registerComponent(new BeanComponentDefinition(beanDef, HANDLER_MAPPING_BEAN_NAME));
handlerMappingBeanDef = beanDef;
} else {
handlerMappingBeanDef = registry.getBeanDefinition(HANDLER_MAPPING_BEAN_NAME);
}
for (Map.Entry<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);
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,40 +16,89 @@
package org.springframework.web.servlet.config;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.context.config.AbstractSpecificationBeanDefinitionParser;
import org.springframework.context.config.FeatureSpecification;
import org.springframework.util.StringUtils;
import java.util.Map;
import org.w3c.dom.Element;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.core.Ordered;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter;
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
/**
* {@link org.springframework.beans.factory.xml.BeanDefinitionParser} that parses a
* {@code resources} element.
* {@code resources} element to register a {@link ResourceHttpRequestHandler}.
* Will also register a {@link SimpleUrlHandlerMapping} for mapping resource requests,
* and a {@link HttpRequestHandlerAdapter} if necessary.
*
* @author Rossen Stoyanchev
* @author Keith Donald
* @author Jeremy Grelle
* @since 3.0.4
* @see MvcResources
* @see MvcResourcesExecutor
*/
class ResourcesBeanDefinitionParser extends AbstractSpecificationBeanDefinitionParser {
class ResourcesBeanDefinitionParser extends AbstractHttpRequestHandlerBeanDefinitionParser implements BeanDefinitionParser {
/**
* Parses the {@code <mvc:resources/>} tag
*/
public FeatureSpecification doParse(Element element, ParserContext parserContext) {
String mapping = element.getAttribute("mapping");
String[] locations =
StringUtils.commaDelimitedListToStringArray(element.getAttribute("location"));
MvcResources spec = new MvcResources(mapping, locations);
if (element.hasAttribute("cache-period")) {
spec.cachePeriod(element.getAttribute("cache-period"));
@Override
public void doParse(Element element, ParserContext parserContext) {
Object source = parserContext.extractSource(element);
registerResourceMappings(parserContext, element, source);
}
private void registerResourceMappings(ParserContext parserContext, Element element, Object source) {
String resourceHandlerName = registerResourceHandler(parserContext, element, source);
if (resourceHandlerName == null) {
return;
}
if (element.hasAttribute("order")) {
spec.order(element.getAttribute("order"));
Map<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;
}
urlMap.put(resourceRequestPath, resourceHandlerName);
RootBeanDefinition handlerMappingDef = new RootBeanDefinition(SimpleUrlHandlerMapping.class);
handlerMappingDef.setSource(source);
handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
handlerMappingDef.getPropertyValues().add("urlMap", urlMap);
String order = element.getAttribute("order");
// use a default of near-lowest precedence, still allowing for even lower precedence in other mappings
handlerMappingDef.getPropertyValues().add("order", StringUtils.hasText(order) ? order : Ordered.LOWEST_PRECEDENCE - 1);
String beanName = parserContext.getReaderContext().generateBeanName(handlerMappingDef);
parserContext.getRegistry().registerBeanDefinition(beanName, handlerMappingDef);
parserContext.registerComponent(new BeanComponentDefinition(handlerMappingDef, beanName));
}
private String registerResourceHandler(ParserContext parserContext, Element element, Object source) {
String locationAttr = element.getAttribute("location");
if (!StringUtils.hasText(locationAttr)) {
parserContext.getReaderContext().error("The 'location' attribute is required.", parserContext.extractSource(element));
return null;
}
RootBeanDefinition resourceHandlerDef = new RootBeanDefinition(ResourceHttpRequestHandler.class);
resourceHandlerDef.setSource(source);
resourceHandlerDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
resourceHandlerDef.getPropertyValues().add("locations", StringUtils.commaDelimitedListToStringArray(locationAttr));
String cacheSeconds = element.getAttribute("cache-period");
if (StringUtils.hasText(cacheSeconds)) {
resourceHandlerDef.getPropertyValues().add("cacheSeconds", cacheSeconds);
}
return spec;
String beanName = parserContext.getReaderContext().generateBeanName(resourceHandlerDef);
parserContext.getRegistry().registerBeanDefinition(beanName, resourceHandlerDef);
parserContext.registerComponent(new BeanComponentDefinition(resourceHandlerDef, beanName));
return beanName;
}
}

View File

@@ -16,30 +16,88 @@
package org.springframework.web.servlet.config;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.context.config.AbstractSpecificationBeanDefinitionParser;
import org.springframework.context.config.FeatureSpecification;
import org.springframework.web.servlet.mvc.ParameterizableViewController;
import java.util.Map;
import org.w3c.dom.Element;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
import org.springframework.web.servlet.mvc.ParameterizableViewController;
import org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter;
/**
* {@link org.springframework.beans.factory.xml.BeanDefinitionParser} that parses a
* {@code view-controller} element to register a {@link ParameterizableViewController}.
* Will also register a {@link SimpleUrlHandlerMapping} for view controllers.
*
* @author Rossen Stoyanchev
* @author Keith Donald
* @author Christian Dupuis
* @since 3.0
* @see MvcViewControllers
* @see MvcViewControllersExecutor
*/
class ViewControllerBeanDefinitionParser extends AbstractSpecificationBeanDefinitionParser {
class ViewControllerBeanDefinitionParser implements BeanDefinitionParser {
/**
* Parses the {@code <mvc:view-controller/>} tag.
*/
public FeatureSpecification doParse(Element element, ParserContext parserContext) {
String path = element.getAttribute("path");
String viewName = element.getAttribute("view-name");
return new MvcViewControllers(path, viewName.isEmpty() ? null : viewName);
private static final String HANDLER_ADAPTER_BEAN_NAME =
"org.springframework.web.servlet.config.viewControllerHandlerAdapter";
private static final String HANDLER_MAPPING_BEAN_NAME =
"org.springframework.web.servlet.config.viewControllerHandlerMapping";
public BeanDefinition parse(Element element, ParserContext parserContext) {
Object source = parserContext.extractSource(element);
// Register handler adapter
registerHanderAdapter(parserContext, source);
// Register handler mapping
BeanDefinition handlerMappingDef = registerHandlerMapping(parserContext, source);
// Create view controller bean definition
RootBeanDefinition viewControllerDef = new RootBeanDefinition(ParameterizableViewController.class);
viewControllerDef.setSource(source);
if (element.hasAttribute("view-name")) {
viewControllerDef.getPropertyValues().add("viewName", element.getAttribute("view-name"));
}
Map<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);
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);
}
}
}