diff --git a/spring-web/src/main/java/org/springframework/web/accept/ContentNegotiationManager.java b/spring-web/src/main/java/org/springframework/web/accept/ContentNegotiationManager.java
index 285f547c57..f87d5495f8 100644
--- a/spring-web/src/main/java/org/springframework/web/accept/ContentNegotiationManager.java
+++ b/spring-web/src/main/java/org/springframework/web/accept/ContentNegotiationManager.java
@@ -30,10 +30,19 @@ import org.springframework.web.context.request.NativeWebRequest;
/**
* This class is used to determine the requested {@linkplain MediaType media types}
- * in a request by delegating to a list of {@link ContentNegotiationStrategy} instances.
+ * of a request by delegating to a list of ContentNegotiationStrategy instances.
+ * The strategies must be provided at instantiation or alternatively if using
+ * the default constructor, an instance of {@link HeaderContentNegotiationStrategy}
+ * will be configured by default.
*
- *
It may also be used to determine the extensions associated with a MediaType by
- * delegating to a list of {@link MediaTypeFileExtensionResolver} instances.
+ *
This class may also be used to look up file extensions associated with a
+ * MediaType. This is done by consulting the list of configured
+ * {@link MediaTypeFileExtensionResolver} instances. Note that some
+ * ContentNegotiationStrategy implementations also implement
+ * MediaTypeFileExtensionResolver and the class constructor accepting the former
+ * will also detect if they implement the latter. If you need to register additional
+ * resolvers, you can use the method
+ * {@link #addFileExtensionResolvers(MediaTypeFileExtensionResolver...)}.
*
* @author Rossen Stoyanchev
* @since 3.2
@@ -50,6 +59,7 @@ public class ContentNegotiationManager implements ContentNegotiationStrategy, Me
* Create an instance with the given ContentNegotiationStrategy instances.
*
Each instance is checked to see if it is also an implementation of
* MediaTypeFileExtensionResolver, and if so it is registered as such.
+ * @param strategies one more more ContentNegotiationStrategy instances
*/
public ContentNegotiationManager(ContentNegotiationStrategy... strategies) {
Assert.notEmpty(strategies, "At least one ContentNegotiationStrategy is expected");
@@ -70,6 +80,11 @@ public class ContentNegotiationManager implements ContentNegotiationStrategy, Me
/**
* Add MediaTypeFileExtensionResolver instances.
+ *
Note that some {@link ContentNegotiationStrategy} implementations also
+ * implement {@link MediaTypeFileExtensionResolver} and the class constructor
+ * accepting the former will also detect implementations of the latter. Therefore
+ * you only need to use this method to register additional instances.
+ * @param one more resolvers
*/
public void addFileExtensionResolvers(MediaTypeFileExtensionResolver... resolvers) {
this.fileExtensionResolvers.addAll(Arrays.asList(resolvers));
diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParser.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParser.java
index cf0dafb584..89ba05baf6 100644
--- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParser.java
+++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParser.java
@@ -16,7 +16,10 @@
package org.springframework.web.servlet.config;
+import java.util.Arrays;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
@@ -29,6 +32,7 @@ import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.format.support.FormattingConversionServiceFactoryBean;
+import org.springframework.http.MediaType;
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.ResourceHttpMessageConverter;
@@ -44,6 +48,9 @@ import org.springframework.util.ClassUtils;
import org.springframework.util.xml.DomUtils;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.HttpRequestHandler;
+import org.springframework.web.accept.ContentNegotiationManager;
+import org.springframework.web.accept.HeaderContentNegotiationStrategy;
+import org.springframework.web.accept.PathExtensionContentNegotiationStrategy;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
@@ -102,9 +109,10 @@ import org.w3c.dom.Element;
*
*
*
Both the {@link RequestMappingHandlerAdapter} and the
- * {@link ExceptionHandlerExceptionResolver} are configured with default
- * instances of the following kind, unless custom instances are provided:
+ * {@link ExceptionHandlerExceptionResolver} are configured with instances of
+ * the following by default:
*
+ *
A {@link ContentNegotiationManager}
*
A {@link DefaultFormattingConversionService}
*
A {@link LocalValidatorFactoryBean} if a JSR-303 implementation is
* available on the classpath
@@ -143,11 +151,14 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source);
parserContext.pushContainingComponent(compDefinition);
- RootBeanDefinition methodMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);
- methodMappingDef.setSource(source);
- methodMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
- methodMappingDef.getPropertyValues().add("order", 0);
- String methodMappingName = parserContext.getReaderContext().registerWithGeneratedName(methodMappingDef);
+ RuntimeBeanReference contentNegotiationManager = getContentNegotiationManager(element, source, parserContext);
+
+ RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);
+ handlerMappingDef.setSource(source);
+ handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
+ handlerMappingDef.getPropertyValues().add("order", 0);
+ handlerMappingDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
+ String methodMappingName = parserContext.getReaderContext().registerWithGeneratedName(handlerMappingDef);
RuntimeBeanReference conversionService = getConversionService(element, source, parserContext);
RuntimeBeanReference validator = getValidator(element, source, parserContext);
@@ -164,22 +175,23 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
ManagedList> argumentResolvers = getArgumentResolvers(element, source, parserContext);
ManagedList> returnValueHandlers = getReturnValueHandlers(element, source, parserContext);
- RootBeanDefinition methodAdapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
- methodAdapterDef.setSource(source);
- methodAdapterDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
- methodAdapterDef.getPropertyValues().add("webBindingInitializer", bindingDef);
- methodAdapterDef.getPropertyValues().add("messageConverters", messageConverters);
+ RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
+ handlerAdapterDef.setSource(source);
+ handlerAdapterDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
+ handlerAdapterDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
+ handlerAdapterDef.getPropertyValues().add("webBindingInitializer", bindingDef);
+ handlerAdapterDef.getPropertyValues().add("messageConverters", messageConverters);
if (element.hasAttribute("ignoreDefaultModelOnRedirect")) {
Boolean ignoreDefaultModel = Boolean.valueOf(element.getAttribute("ignoreDefaultModelOnRedirect"));
- methodAdapterDef.getPropertyValues().add("ignoreDefaultModelOnRedirect", ignoreDefaultModel);
+ handlerAdapterDef.getPropertyValues().add("ignoreDefaultModelOnRedirect", ignoreDefaultModel);
}
if (argumentResolvers != null) {
- methodAdapterDef.getPropertyValues().add("customArgumentResolvers", argumentResolvers);
+ handlerAdapterDef.getPropertyValues().add("customArgumentResolvers", argumentResolvers);
}
if (returnValueHandlers != null) {
- methodAdapterDef.getPropertyValues().add("customReturnValueHandlers", returnValueHandlers);
+ handlerAdapterDef.getPropertyValues().add("customReturnValueHandlers", returnValueHandlers);
}
- String methodAdapterName = parserContext.getReaderContext().registerWithGeneratedName(methodAdapterDef);
+ String handlerAdapterName = parserContext.getReaderContext().registerWithGeneratedName(handlerAdapterDef);
RootBeanDefinition csInterceptorDef = new RootBeanDefinition(ConversionServiceExposingInterceptor.class);
csInterceptorDef.setSource(source);
@@ -191,13 +203,14 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
mappedCsInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(1, csInterceptorDef);
String mappedInterceptorName = parserContext.getReaderContext().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);
+ RootBeanDefinition exceptionHandlerExceptionResolver = new RootBeanDefinition(ExceptionHandlerExceptionResolver.class);
+ exceptionHandlerExceptionResolver.setSource(source);
+ exceptionHandlerExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
+ exceptionHandlerExceptionResolver.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
+ exceptionHandlerExceptionResolver.getPropertyValues().add("messageConverters", messageConverters);
+ exceptionHandlerExceptionResolver.getPropertyValues().add("order", 0);
String methodExceptionResolverName =
- parserContext.getReaderContext().registerWithGeneratedName(methodExceptionResolver);
+ parserContext.getReaderContext().registerWithGeneratedName(exceptionHandlerExceptionResolver);
RootBeanDefinition responseStatusExceptionResolver = new RootBeanDefinition(ResponseStatusExceptionResolver.class);
responseStatusExceptionResolver.setSource(source);
@@ -213,9 +226,9 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
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(handlerMappingDef, methodMappingName));
+ parserContext.registerComponent(new BeanComponentDefinition(handlerAdapterDef, handlerAdapterName));
+ parserContext.registerComponent(new BeanComponentDefinition(exceptionHandlerExceptionResolver, methodExceptionResolverName));
parserContext.registerComponent(new BeanComponentDefinition(responseStatusExceptionResolver, responseStatusExceptionResolverName));
parserContext.registerComponent(new BeanComponentDefinition(defaultExceptionResolver, defaultExceptionResolverName));
parserContext.registerComponent(new BeanComponentDefinition(mappedCsInterceptorDef, mappedInterceptorName));
@@ -261,6 +274,42 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
}
}
+ private RuntimeBeanReference getContentNegotiationManager(Element element, Object source, ParserContext parserContext) {
+ RuntimeBeanReference contentNegotiationManagerRef;
+ if (element.hasAttribute("content-negotiation-manager")) {
+ contentNegotiationManagerRef = new RuntimeBeanReference(element.getAttribute("content-negotiation-manager"));
+ }
+ else {
+ RootBeanDefinition managerDef = new RootBeanDefinition(ContentNegotiationManager.class);
+ managerDef.setSource(source);
+ managerDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
+ PathExtensionContentNegotiationStrategy strategy1 = new PathExtensionContentNegotiationStrategy(getDefaultMediaTypes());
+ HeaderContentNegotiationStrategy strategy2 = new HeaderContentNegotiationStrategy();
+ managerDef.getConstructorArgumentValues().addIndexedArgumentValue(0, Arrays.asList(strategy1,strategy2));
+
+ String beanName = "mvcContentNegotiationManager";
+ parserContext.getReaderContext().getRegistry().registerBeanDefinition(beanName , managerDef);
+ parserContext.registerComponent(new BeanComponentDefinition(managerDef, beanName));
+ contentNegotiationManagerRef = new RuntimeBeanReference(beanName);
+ }
+ return contentNegotiationManagerRef;
+ }
+
+ private Map getDefaultMediaTypes() {
+ Map map = new HashMap();
+ if (romePresent) {
+ map.put("atom", MediaType.APPLICATION_ATOM_XML);
+ map.put("rss", MediaType.valueOf("application/rss+xml"));
+ }
+ if (jackson2Present || jacksonPresent) {
+ map.put("json", MediaType.APPLICATION_JSON);
+ }
+ if (jaxb2Present) {
+ map.put("xml", MediaType.APPLICATION_XML);
+ }
+ return map;
+ }
+
private RuntimeBeanReference getMessageCodesResolver(Element element, Object source, ParserContext parserContext) {
if (element.hasAttribute("message-codes-resolver")) {
return new RuntimeBeanReference(element.getAttribute("message-codes-resolver"));
diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ContentNegotiationConfigurer.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ContentNegotiationConfigurer.java
new file mode 100644
index 0000000000..8468a365b3
--- /dev/null
+++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ContentNegotiationConfigurer.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2002-2012 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.annotation;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.servlet.ServletContext;
+
+import org.springframework.http.MediaType;
+import org.springframework.util.CollectionUtils;
+import org.springframework.web.accept.ContentNegotiationManager;
+import org.springframework.web.accept.ContentNegotiationStrategy;
+import org.springframework.web.accept.FixedContentNegotiationStrategy;
+import org.springframework.web.accept.HeaderContentNegotiationStrategy;
+import org.springframework.web.accept.ParameterContentNegotiationStrategy;
+import org.springframework.web.accept.PathExtensionContentNegotiationStrategy;
+
+/**
+ * Helps with configuring a {@link ContentNegotiationManager}.
+ *
+ *
By default the extension of the request path extension is checked first and
+ * the {@code Accept} is checked second. The path extension check will perform a
+ * look up in the media types configured via {@link #setMediaTypes(Map)} and
+ * will also fall back to {@link ServletContext} and the Java Activation Framework
+ * (if present).
+ *
+ * @author Rossen Stoyanchev
+ * @since 3.2
+ */
+public class ContentNegotiationConfigurer {
+
+ private boolean favorPathExtension = true;
+
+ private boolean favorParameter = false;
+
+ private boolean ignoreAcceptHeader = false;
+
+ private Map mediaTypes = new HashMap();
+
+ private Boolean useJaf;
+
+ private String parameterName;
+
+ private MediaType defaultContentType;
+
+ /**
+ * Indicate whether the extension of the request path should be used to determine
+ * the requested media type with the highest priority.
+ *
By default this value is set to {@code true} in which case a request
+ * for {@code /hotels.pdf} will be interpreted as a request for
+ * {@code "application/pdf"} regardless of the {@code Accept} header.
+ */
+ public ContentNegotiationConfigurer setFavorPathExtension(boolean favorPathExtension) {
+ this.favorPathExtension = favorPathExtension;
+ return this;
+ }
+
+ /**
+ * Add mappings from file extensions to media types.
+ *
If this property is not set, the Java Action Framework, if available, may
+ * still be used in conjunction with {@link #setFavorPathExtension(boolean)}.
+ */
+ public ContentNegotiationConfigurer addMediaTypes(Map mediaTypes) {
+ if (!CollectionUtils.isEmpty(mediaTypes)) {
+ for (Map.Entry entry : mediaTypes.entrySet()) {
+ String extension = entry.getKey().toLowerCase(Locale.ENGLISH);
+ this.mediaTypes.put(extension, entry.getValue());
+ }
+ }
+ return this;
+ }
+
+ /**
+ * Add mappings from file extensions to media types replacing any previous mappings.
+ *
If this property is not set, the Java Action Framework, if available, may
+ * still be used in conjunction with {@link #setFavorPathExtension(boolean)}.
+ */
+ public ContentNegotiationConfigurer replaceMediaTypes(Map mediaTypes) {
+ this.mediaTypes.clear();
+ if (!CollectionUtils.isEmpty(mediaTypes)) {
+ for (Map.Entry entry : mediaTypes.entrySet()) {
+ String extension = entry.getKey().toLowerCase(Locale.ENGLISH);
+ this.mediaTypes.put(extension, entry.getValue());
+ }
+ }
+ return this;
+ }
+
+ /**
+ * Indicate whether to use the Java Activation Framework as a fallback option
+ * to map from file extensions to media types. This is used only when
+ * {@link #setFavorPathExtension(boolean)} is set to {@code true}.
+ *
The default value is {@code true}.
+ * @see #parameterName
+ * @see #setMediaTypes(Map)
+ */
+ public ContentNegotiationConfigurer setUseJaf(boolean useJaf) {
+ this.useJaf = useJaf;
+ return this;
+ }
+
+ /**
+ * Indicate whether a request parameter should be used to determine the
+ * requested media type with the 2nd highest priority, i.e.
+ * after path extensions but before the {@code Accept} header.
+ *
The default value is {@code false}. If set to to {@code true}, a request
+ * for {@code /hotels?format=pdf} will be interpreted as a request for
+ * {@code "application/pdf"} regardless of the {@code Accept} header.
+ *
To use this option effectively you must also configure the MediaType
+ * type mappings via {@link #setMediaTypes(Map)}.
+ * @see #setParameterName(String)
+ */
+ public ContentNegotiationConfigurer setFavorParameter(boolean favorParameter) {
+ this.favorParameter = favorParameter;
+ return this;
+ }
+
+ /**
+ * Set the parameter name that can be used to determine the requested media type
+ * if the {@link #setFavorParameter} property is {@code true}.
+ *
The default parameter name is {@code "format"}.
+ */
+ public ContentNegotiationConfigurer setParameterName(String parameterName) {
+ this.parameterName = parameterName;
+ return this;
+ }
+
+ /**
+ * Indicate whether the HTTP {@code Accept} header should be ignored altogether.
+ * If set the {@code Accept} header is checked at the
+ * 3rd highest priority, i.e. after the request path extension and
+ * possibly a request parameter if configured.
+ *
By default this value is set to {@code false}.
+ */
+ public ContentNegotiationConfigurer setIgnoreAcceptHeader(boolean ignoreAcceptHeader) {
+ this.ignoreAcceptHeader = ignoreAcceptHeader;
+ return this;
+ }
+
+ /**
+ * Set the default content type.
+ *
This content type will be used when neither the request path extension,
+ * nor a request parameter, nor the {@code Accept} header could help determine
+ * the requested content type.
+ */
+ public ContentNegotiationConfigurer setDefaultContentType(MediaType defaultContentType) {
+ this.defaultContentType = defaultContentType;
+ return this;
+ }
+
+ /**
+ * @return the configured {@link ContentNegotiationManager} instance
+ */
+ protected ContentNegotiationManager getContentNegotiationManager() {
+ List strategies = new ArrayList();
+ if (this.favorPathExtension) {
+ PathExtensionContentNegotiationStrategy strategy = new PathExtensionContentNegotiationStrategy(this.mediaTypes);
+ if (this.useJaf != null) {
+ strategy.setUseJaf(this.useJaf);
+ }
+ strategies.add(strategy);
+ }
+ if (this.favorParameter) {
+ ParameterContentNegotiationStrategy strategy = new ParameterContentNegotiationStrategy(this.mediaTypes);
+ strategy.setParameterName(this.parameterName);
+ strategies.add(strategy);
+ }
+ if (!this.ignoreAcceptHeader) {
+ strategies.add(new HeaderContentNegotiationStrategy());
+ }
+ if (this.defaultContentType != null) {
+ strategies.add(new FixedContentNegotiationStrategy(this.defaultContentType));
+ }
+ ContentNegotiationStrategy[] array = strategies.toArray(new ContentNegotiationStrategy[strategies.size()]);
+ return new ContentNegotiationManager(array);
+ }
+
+}
diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfiguration.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfiguration.java
index 82cde7ca16..d0537a812c 100644
--- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfiguration.java
+++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfiguration.java
@@ -55,6 +55,11 @@ public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
this.configurers.addInterceptors(registry);
}
+ @Override
+ protected void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
+ this.configurers.configureContentNegotiation(configurer);
+ }
+
@Override
protected void addViewControllers(ViewControllerRegistry registry) {
this.configurers.addViewControllers(registry);
diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/InterceptorRegistry.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/InterceptorRegistry.java
index 7988a67c70..5e2f45eecf 100644
--- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/InterceptorRegistry.java
+++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/InterceptorRegistry.java
@@ -24,23 +24,22 @@ import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.handler.WebRequestHandlerInterceptorAdapter;
/**
- * Stores and provides access to a list of interceptors. For each interceptor you can optionally
- * specify one or more URL patterns it applies to.
+ * Helps with configuring a list of mapped interceptors.
*
* @author Rossen Stoyanchev
* @author Keith Donald
- *
+ *
* @since 3.1
*/
public class InterceptorRegistry {
private final List registrations = new ArrayList();
-
+
/**
- * Adds the provided {@link HandlerInterceptor}.
+ * Adds the provided {@link HandlerInterceptor}.
* @param interceptor the interceptor to add
- * @return An {@link InterceptorRegistration} that allows you optionally configure the
- * registered interceptor further for example adding URL patterns it should apply to.
+ * @return An {@link InterceptorRegistration} that allows you optionally configure the
+ * registered interceptor further for example adding URL patterns it should apply to.
*/
public InterceptorRegistration addInterceptor(HandlerInterceptor interceptor) {
InterceptorRegistration registration = new InterceptorRegistration(interceptor);
@@ -49,10 +48,10 @@ public class InterceptorRegistry {
}
/**
- * Adds the provided {@link WebRequestInterceptor}.
+ * Adds the provided {@link WebRequestInterceptor}.
* @param interceptor the interceptor to add
- * @return An {@link InterceptorRegistration} that allows you optionally configure the
- * registered interceptor further for example adding URL patterns it should apply to.
+ * @return An {@link InterceptorRegistration} that allows you optionally configure the
+ * registered interceptor further for example adding URL patterns it should apply to.
*/
public InterceptorRegistration addWebRequestInterceptor(WebRequestInterceptor interceptor) {
WebRequestHandlerInterceptorAdapter adapted = new WebRequestHandlerInterceptorAdapter(interceptor);
diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java
index 44a75784fc..a759cbe733 100644
--- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java
+++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java
@@ -17,7 +17,9 @@
package org.springframework.web.servlet.config.annotation;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
@@ -35,6 +37,7 @@ import org.springframework.format.Formatter;
import org.springframework.format.FormatterRegistry;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.format.support.FormattingConversionService;
+import org.springframework.http.MediaType;
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.ResourceHttpMessageConverter;
@@ -52,6 +55,7 @@ import org.springframework.validation.MessageCodesResolver;
import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.HttpRequestHandler;
+import org.springframework.web.accept.ContentNegotiationManager;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
@@ -120,8 +124,9 @@ import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolv
*
*
Both the {@link RequestMappingHandlerAdapter} and the
* {@link ExceptionHandlerExceptionResolver} are configured with default
- * instances of the following kind, unless custom instances are provided:
+ * instances of the following by default:
*
+ *
A {@link ContentNegotiationManager}
*
A {@link DefaultFormattingConversionService}
*
A {@link LocalValidatorFactoryBean} if a JSR-303 implementation is
* available on the classpath
@@ -158,6 +163,8 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
private List