diff --git a/spring-web/src/main/java/org/springframework/web/accept/ContentNegotiationManagerFactoryBean.java b/spring-web/src/main/java/org/springframework/web/accept/ContentNegotiationManagerFactoryBean.java index fbe1b719251..14565545756 100644 --- a/spring-web/src/main/java/org/springframework/web/accept/ContentNegotiationManagerFactoryBean.java +++ b/spring-web/src/main/java/org/springframework/web/accept/ContentNegotiationManagerFactoryBean.java @@ -28,6 +28,7 @@ import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.http.MediaType; import org.springframework.util.CollectionUtils; +import org.springframework.web.context.ServletContextAware; /** * A factory providing convenient access to a {@code ContentNegotiationManager} @@ -41,7 +42,8 @@ import org.springframework.util.CollectionUtils; * @author Rossen Stoyanchev * @since 3.2 */ -public class ContentNegotiationManagerFactoryBean implements FactoryBean, InitializingBean { +public class ContentNegotiationManagerFactoryBean + implements FactoryBean, InitializingBean, ServletContextAware { private boolean favorPathExtension = true; @@ -49,7 +51,7 @@ public class ContentNegotiationManagerFactoryBean implements FactoryBean mediaTypes = new HashMap(); + private Properties mediaTypes = new Properties(); private Boolean useJaf; @@ -59,6 +61,9 @@ public class ContentNegotiationManagerFactoryBean implements FactoryBeanhighest priority. @@ -84,6 +89,10 @@ public class ContentNegotiationManagerFactoryBean implements FactoryBean strategies = new ArrayList(); + Map mediaTypesMap = new HashMap(); + CollectionUtils.mergePropertiesIntoMap(this.mediaTypes, mediaTypesMap); + if (this.favorPathExtension) { - PathExtensionContentNegotiationStrategy strategy = new PathExtensionContentNegotiationStrategy(this.mediaTypes); + PathExtensionContentNegotiationStrategy strategy; + if (this.servletContext != null) { + strategy = new ServletPathExtensionContentNegotiationStrategy(this.servletContext, mediaTypesMap); + } + else { + strategy = new PathExtensionContentNegotiationStrategy(mediaTypesMap); + } if (this.useJaf != null) { strategy.setUseJaf(this.useJaf); } @@ -153,7 +175,7 @@ public class ContentNegotiationManagerFactoryBean implements FactoryBean - *
  • Look upin the map of media types provided to the constructor - *
  • Call to {@link ServletContext#getMimeType(String)} - *
  • Use the Java Activation framework - * - * - *

    The presence of the Java Activation framework is detected and enabled automatically - * but the {@link #setUseJaf(boolean)} property may be used to override that setting. + *

    + * The presence of the Java Activation framework is detected and enabled + * automatically but the {@link #setUseJaf(boolean)} property may be used to + * override that setting. * * @author Rossen Stoyanchev * @since 3.2 */ public class PathExtensionContentNegotiationStrategy extends AbstractMappingContentNegotiationStrategy { - private static final boolean JAF_PRESENT = - ClassUtils.isPresent("javax.activation.FileTypeMap", PathExtensionContentNegotiationStrategy.class.getClassLoader()); + private static final boolean JAF_PRESENT = ClassUtils.isPresent("javax.activation.FileTypeMap", + PathExtensionContentNegotiationStrategy.class.getClassLoader()); private static final Log logger = LogFactory.getLog(PathExtensionContentNegotiationStrategy.class); @@ -68,6 +65,7 @@ public class PathExtensionContentNegotiationStrategy extends AbstractMappingCont private boolean useJaf = JAF_PRESENT; + /** * Create an instance with the given extension-to-MediaType lookup. * @throws IllegalArgumentException if a media type string cannot be parsed @@ -78,8 +76,7 @@ public class PathExtensionContentNegotiationStrategy extends AbstractMappingCont /** * Create an instance without any mappings to start with. Mappings may be added - * later on if any extensions are resolved through {@link ServletContext#getMimeType(String)} - * or through the Java Activation framework. + * later on if any extensions are resolved through the Java Activation framework. */ public PathExtensionContentNegotiationStrategy() { super(null); @@ -112,21 +109,13 @@ public class PathExtensionContentNegotiationStrategy extends AbstractMappingCont @Override protected MediaType handleNoMatch(NativeWebRequest webRequest, String extension) { - MediaType mediaType = null; - HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class); - if (servletRequest != null) { - String mimeType = servletRequest.getServletContext().getMimeType("file." + extension); - if (StringUtils.hasText(mimeType)) { - mediaType = MediaType.parseMediaType(mimeType); - } - } - if ((mediaType == null || MediaType.APPLICATION_OCTET_STREAM.equals(mediaType)) && this.useJaf) { + if (this.useJaf) { MediaType jafMediaType = JafMediaTypeFactory.getMediaType("file." + extension); if (jafMediaType != null && !MediaType.APPLICATION_OCTET_STREAM.equals(jafMediaType)) { - mediaType = jafMediaType; + return jafMediaType; } } - return mediaType; + return null; } diff --git a/spring-web/src/main/java/org/springframework/web/accept/ServletPathExtensionContentNegotiationStrategy.java b/spring-web/src/main/java/org/springframework/web/accept/ServletPathExtensionContentNegotiationStrategy.java new file mode 100644 index 00000000000..4e8ad8a317a --- /dev/null +++ b/spring-web/src/main/java/org/springframework/web/accept/ServletPathExtensionContentNegotiationStrategy.java @@ -0,0 +1,84 @@ +/* + * 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.accept; + +import java.util.Map; + +import javax.servlet.ServletContext; + +import org.springframework.http.MediaType; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; +import org.springframework.web.context.request.NativeWebRequest; + +/** + * An extension of {@code PathExtensionContentNegotiationStrategy} that uses + * {@link ServletContext#getMimeType(String)} as a fallback mechanism when + * matching a path extension to a media type. + * + * @author Rossen Stoyanchev + * @since 3.2 + */ +public class ServletPathExtensionContentNegotiationStrategy extends PathExtensionContentNegotiationStrategy { + + private final ServletContext servletContext; + + + /** + * Create an instance with the given extension-to-MediaType lookup. + * @throws IllegalArgumentException if a media type string cannot be parsed + */ + public ServletPathExtensionContentNegotiationStrategy( + ServletContext servletContext, Map mediaTypes) { + + super(mediaTypes); + Assert.notNull(servletContext, "ServletContext is required!"); + this.servletContext = servletContext; + } + + /** + * Create an instance without any mappings to start with. Mappings may be + * added later on if any extensions are resolved through + * {@link ServletContext#getMimeType(String)} or through the Java Activation + * framework. + */ + public ServletPathExtensionContentNegotiationStrategy(ServletContext servletContext) { + this(servletContext, null); + } + + /** + * Look up the given extension via {@link ServletContext#getMimeType(String)} + * and if that doesn't help, delegate to the parent implementation. + */ + @Override + protected MediaType handleNoMatch(NativeWebRequest webRequest, String extension) { + MediaType mediaType = null; + if (this.servletContext != null) { + String mimeType = this.servletContext.getMimeType("file." + extension); + if (StringUtils.hasText(mimeType)) { + mediaType = MediaType.parseMediaType(mimeType); + } + } + if (mediaType == null || MediaType.APPLICATION_OCTET_STREAM.equals(mediaType)) { + MediaType superMediaType = super.handleNoMatch(webRequest, extension); + if (superMediaType != null) { + mediaType = superMediaType; + } + } + return mediaType; + } + +} diff --git a/spring-web/src/test/java/org/springframework/web/accept/ContentNegotiationManagerFactoryBeanTests.java b/spring-web/src/test/java/org/springframework/web/accept/ContentNegotiationManagerFactoryBeanTests.java index cbdb2c8ae71..75b27436def 100644 --- a/spring-web/src/test/java/org/springframework/web/accept/ContentNegotiationManagerFactoryBeanTests.java +++ b/spring-web/src/test/java/org/springframework/web/accept/ContentNegotiationManagerFactoryBeanTests.java @@ -42,9 +42,11 @@ public class ContentNegotiationManagerFactoryBeanTests { @Before public void setup() { - this.factoryBean = new ContentNegotiationManagerFactoryBean(); this.servletRequest = new MockHttpServletRequest(); this.webRequest = new ServletWebRequest(this.servletRequest); + + this.factoryBean = new ContentNegotiationManagerFactoryBean(); + this.factoryBean.setServletContext(this.servletRequest.getServletContext()); } @Test diff --git a/spring-web/src/test/java/org/springframework/web/accept/PathExtensionContentNegotiationStrategyTests.java b/spring-web/src/test/java/org/springframework/web/accept/PathExtensionContentNegotiationStrategyTests.java index c5922d7a36a..cde78fa2ea7 100644 --- a/spring-web/src/test/java/org/springframework/web/accept/PathExtensionContentNegotiationStrategyTests.java +++ b/spring-web/src/test/java/org/springframework/web/accept/PathExtensionContentNegotiationStrategyTests.java @@ -22,6 +22,8 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import javax.servlet.ServletContext; + import org.junit.Before; import org.junit.Test; import org.springframework.http.MediaType; @@ -44,7 +46,7 @@ public class PathExtensionContentNegotiationStrategyTests { @Before public void setup() { this.servletRequest = new MockHttpServletRequest(); - this.webRequest = new ServletWebRequest(servletRequest ); + this.webRequest = new ServletWebRequest(servletRequest); } @Test @@ -74,8 +76,12 @@ public class PathExtensionContentNegotiationStrategyTests { @Test public void getMediaTypeFromFilenameNoJaf() { + this.servletRequest.setRequestURI("test.xls"); - PathExtensionContentNegotiationStrategy strategy = new PathExtensionContentNegotiationStrategy(); + + ServletContext servletContext = this.servletRequest.getServletContext(); + PathExtensionContentNegotiationStrategy strategy = + new ServletPathExtensionContentNegotiationStrategy(servletContext); strategy.setUseJaf(false); List mediaTypes = strategy.resolveMediaTypes(this.webRequest); 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 ba799a7b4bc..b86d5c59512 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,10 +16,8 @@ package org.springframework.web.servlet.config; -import java.util.Arrays; -import java.util.HashMap; import java.util.List; -import java.util.Map; +import java.util.Properties; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionHolder; @@ -49,8 +47,7 @@ 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.accept.ContentNegotiationManagerFactoryBean; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.support.ConfigurableWebBindingInitializer; @@ -289,34 +286,32 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser { 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)); + RootBeanDefinition factoryBeanDef = new RootBeanDefinition(ContentNegotiationManagerFactoryBean.class); + factoryBeanDef.setSource(source); + factoryBeanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + factoryBeanDef.getPropertyValues().add("mediaTypes", getDefaultMediaTypes()); String beanName = "mvcContentNegotiationManager"; - parserContext.getReaderContext().getRegistry().registerBeanDefinition(beanName , managerDef); - parserContext.registerComponent(new BeanComponentDefinition(managerDef, beanName)); + parserContext.getReaderContext().getRegistry().registerBeanDefinition(beanName , factoryBeanDef); + parserContext.registerComponent(new BeanComponentDefinition(factoryBeanDef, beanName)); contentNegotiationManagerRef = new RuntimeBeanReference(beanName); } return contentNegotiationManagerRef; } - private Map getDefaultMediaTypes() { - Map map = new HashMap(); + private Properties getDefaultMediaTypes() { + Properties props = new Properties(); if (romePresent) { - map.put("atom", MediaType.APPLICATION_ATOM_XML); - map.put("rss", MediaType.valueOf("application/rss+xml")); + props.put("atom", MediaType.APPLICATION_ATOM_XML_VALUE); + props.put("rss", "application/rss+xml"); } if (jackson2Present || jacksonPresent) { - map.put("json", MediaType.APPLICATION_JSON); + props.put("json", MediaType.APPLICATION_JSON_VALUE); } if (jaxb2Present) { - map.put("xml", MediaType.APPLICATION_XML); + props.put("xml", MediaType.APPLICATION_XML_VALUE); } - return map; + return props; } private RuntimeBeanReference getMessageCodesResolver(Element element, Object source, ParserContext parserContext) { 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 index 2fb32c6bde8..99666f59813 100644 --- 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 @@ -15,22 +15,13 @@ */ 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; +import org.springframework.web.accept.ContentNegotiationManagerFactoryBean; /** * Helps with configuring a {@link ContentNegotiationManager}. @@ -45,19 +36,15 @@ import org.springframework.web.accept.PathExtensionContentNegotiationStrategy; */ public class ContentNegotiationConfigurer { - private boolean favorPathExtension = true; + private ContentNegotiationManagerFactoryBean factoryBean = new ContentNegotiationManagerFactoryBean(); - private boolean favorParameter = false; - private boolean ignoreAcceptHeader = false; - - private Map mediaTypes = new HashMap(); - - private Boolean useJaf; - - private String parameterName; - - private MediaType defaultContentType; + /** + * Class constructor with {@link javax.servlet.ServletContext}. + */ + public ContentNegotiationConfigurer(ServletContext servletContext) { + this.factoryBean.setServletContext(servletContext); + } /** * Indicate whether the extension of the request path should be used to determine @@ -66,32 +53,29 @@ public class ContentNegotiationConfigurer { * 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; + public ContentNegotiationConfigurer favorPathExtension(boolean favorPathExtension) { + this.factoryBean.setFavorPathExtension(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)}. + * still be used in conjunction with {@link #favorPathExtension(boolean)}. */ - public ContentNegotiationConfigurer addMediaType(String extension, MediaType mediaType) { - this.mediaTypes.put(extension, mediaType); + public ContentNegotiationConfigurer mediaType(String extension, MediaType mediaType) { + this.factoryBean.getMediaTypes().put(extension, mediaType); 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)}. + * still be used in conjunction with {@link #favorPathExtension(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()); - } + public ContentNegotiationConfigurer mediaTypes(Map mediaTypes) { + if (mediaTypes != null) { + this.factoryBean.getMediaTypes().putAll(mediaTypes); } return this; } @@ -99,29 +83,24 @@ public class ContentNegotiationConfigurer { /** * 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)}. + * still be used in conjunction with {@link #favorPathExtension(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()); - } - } + this.factoryBean.getMediaTypes().clear(); + mediaTypes(mediaTypes); 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}. + * {@link #favorPathExtension(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; + public ContentNegotiationConfigurer useJaf(boolean useJaf) { + this.factoryBean.setUseJaf(useJaf); return this; } @@ -134,10 +113,10 @@ public class ContentNegotiationConfigurer { * {@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) + * @see #parameterName(String) */ - public ContentNegotiationConfigurer setFavorParameter(boolean favorParameter) { - this.favorParameter = favorParameter; + public ContentNegotiationConfigurer favorParameter(boolean favorParameter) { + this.factoryBean.setFavorParameter(favorParameter); return this; } @@ -146,8 +125,8 @@ public class ContentNegotiationConfigurer { * if the {@link #setFavorParameter} property is {@code true}. *

    The default parameter name is {@code "format"}. */ - public ContentNegotiationConfigurer setParameterName(String parameterName) { - this.parameterName = parameterName; + public ContentNegotiationConfigurer parameterName(String parameterName) { + this.factoryBean.setParameterName(parameterName); return this; } @@ -158,8 +137,8 @@ public class ContentNegotiationConfigurer { * possibly a request parameter if configured. *

    By default this value is set to {@code false}. */ - public ContentNegotiationConfigurer setIgnoreAcceptHeader(boolean ignoreAcceptHeader) { - this.ignoreAcceptHeader = ignoreAcceptHeader; + public ContentNegotiationConfigurer ignoreAcceptHeader(boolean ignoreAcceptHeader) { + this.factoryBean.setIgnoreAcceptHeader(ignoreAcceptHeader); return this; } @@ -169,36 +148,17 @@ public class ContentNegotiationConfigurer { * nor a request parameter, nor the {@code Accept} header could help determine * the requested content type. */ - public ContentNegotiationConfigurer setDefaultContentType(MediaType defaultContentType) { - this.defaultContentType = defaultContentType; + public ContentNegotiationConfigurer defaultContentType(MediaType defaultContentType) { + this.factoryBean.setDefaultContentType(defaultContentType); return this; } /** - * @return the configured {@link ContentNegotiationManager} instance + * 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); + protected ContentNegotiationManager getContentNegotiationManager() throws Exception { + this.factoryBean.afterPropertiesSet(); + return this.factoryBean.getObject(); } } 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 bf770af17c4..85a64026cbd 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 @@ -167,10 +167,18 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv private List> messageConverters; + + /** + * Set the {@link javax.servlet.ServletContext}, e.g. for resource handling, + * looking up file extensions, etc. + */ public void setServletContext(ServletContext servletContext) { this.servletContext = servletContext; } + /** + * Set the Spring {@link ApplicationContext}, e.g. for resource loading. + */ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } @@ -219,10 +227,15 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv @Bean public ContentNegotiationManager mvcContentNegotiationManager() { if (this.contentNegotiationManager == null) { - ContentNegotiationConfigurer configurer = new ContentNegotiationConfigurer(); - configurer.addMediaTypes(getDefaultMediaTypes()); + ContentNegotiationConfigurer configurer = new ContentNegotiationConfigurer(this.servletContext); + configurer.mediaTypes(getDefaultMediaTypes()); configureContentNegotiation(configurer); - this.contentNegotiationManager = configurer.getContentNegotiationManager(); + try { + this.contentNegotiationManager = configurer.getContentNegotiationManager(); + } + catch (Exception e) { + throw new BeanInitializationException("Could not create ContentNegotiationManager", e); + } } return this.contentNegotiationManager; } @@ -398,9 +411,11 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv try { String className = "org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"; clazz = ClassUtils.forName(className, WebMvcConfigurationSupport.class.getClassLoader()); - } catch (ClassNotFoundException e) { + } + catch (ClassNotFoundException e) { throw new BeanInitializationException("Could not find default validator", e); - } catch (LinkageError e) { + } + catch (LinkageError e) { throw new BeanInitializationException("Could not find default validator", e); } validator = (Validator) BeanUtils.instantiate(clazz); diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/ContentNegotiatingViewResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/ContentNegotiatingViewResolver.java index 47fa87d7b09..ed796ac8bc2 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/ContentNegotiatingViewResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/ContentNegotiatingViewResolver.java @@ -19,7 +19,6 @@ package org.springframework.web.servlet.view; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; @@ -43,11 +42,7 @@ import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import org.springframework.web.HttpMediaTypeNotAcceptableException; import org.springframework.web.accept.ContentNegotiationManager; -import org.springframework.web.accept.FixedContentNegotiationStrategy; -import org.springframework.web.accept.PathExtensionContentNegotiationStrategy; -import org.springframework.web.accept.HeaderContentNegotiationStrategy; -import org.springframework.web.accept.ParameterContentNegotiationStrategy; -import org.springframework.web.accept.ContentNegotiationStrategy; +import org.springframework.web.accept.ContentNegotiationManagerFactoryBean; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; @@ -99,13 +94,7 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport private ContentNegotiationManager contentNegotiationManager; - 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; + private ContentNegotiationManagerFactoryBean cnManagerFactoryBean = new ContentNegotiationManagerFactoryBean(); private boolean useNotAcceptableStatusCode = false; @@ -144,7 +133,7 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport * @deprecated use {@link #setContentNegotiationManager(ContentNegotiationManager)} */ public void setFavorPathExtension(boolean favorPathExtension) { - this.favorPathExtension = favorPathExtension; + this.cnManagerFactoryBean.setFavorParameter(favorPathExtension); } /** @@ -154,7 +143,7 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport * @deprecated use {@link #setContentNegotiationManager(ContentNegotiationManager)} */ public void setUseJaf(boolean useJaf) { - this.useJaf = useJaf; + this.cnManagerFactoryBean.setUseJaf(useJaf); } /** @@ -167,7 +156,7 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport * @deprecated use {@link #setContentNegotiationManager(ContentNegotiationManager)} */ public void setFavorParameter(boolean favorParameter) { - this.favorParameter = favorParameter; + this.cnManagerFactoryBean.setFavorParameter(favorParameter); } /** @@ -177,7 +166,7 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport * @deprecated use {@link #setContentNegotiationManager(ContentNegotiationManager)} */ public void setParameterName(String parameterName) { - this.parameterName = parameterName; + this.cnManagerFactoryBean.setParameterName(parameterName); } /** @@ -189,7 +178,7 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport * @deprecated use {@link #setContentNegotiationManager(ContentNegotiationManager)} */ public void setIgnoreAcceptHeader(boolean ignoreAcceptHeader) { - this.ignoreAcceptHeader = ignoreAcceptHeader; + this.cnManagerFactoryBean.setIgnoreAcceptHeader(ignoreAcceptHeader); } /** @@ -201,11 +190,7 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport */ public void setMediaTypes(Map mediaTypes) { if (mediaTypes != null) { - for (Map.Entry entry : mediaTypes.entrySet()) { - String extension = entry.getKey().toLowerCase(Locale.ENGLISH); - MediaType mediaType = MediaType.parseMediaType(entry.getValue()); - this.mediaTypes.put(extension, mediaType); - } + this.cnManagerFactoryBean.getMediaTypes().putAll(mediaTypes); } } @@ -217,7 +202,7 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport * @deprecated use {@link #setContentNegotiationManager(ContentNegotiationManager)} */ public void setDefaultContentType(MediaType defaultContentType) { - this.defaultContentType = defaultContentType; + this.cnManagerFactoryBean.setDefaultContentType(defaultContentType); } /** @@ -277,31 +262,13 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport "'viewResolvers' property on the ContentNegotiatingViewResolver"); } OrderComparator.sort(this.viewResolvers); + this.cnManagerFactoryBean.setServletContext(servletContext); } public void afterPropertiesSet() throws Exception { if (this.contentNegotiationManager == null) { - 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()]); - this.contentNegotiationManager = new ContentNegotiationManager(array); + this.cnManagerFactoryBean.afterPropertiesSet(); + this.contentNegotiationManager = this.cnManagerFactoryBean.getObject(); } } diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/ContentNegotiationConfigurerTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/ContentNegotiationConfigurerTests.java index 8ca9b4930c2..25294b586a6 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/ContentNegotiationConfigurerTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/ContentNegotiationConfigurerTests.java @@ -42,9 +42,9 @@ public class ContentNegotiationConfigurerTests { @Before public void setup() { - this.configurer = new ContentNegotiationConfigurer(); this.servletRequest = new MockHttpServletRequest(); this.webRequest = new ServletWebRequest(this.servletRequest); + this.configurer = new ContentNegotiationConfigurer(this.servletRequest.getServletContext()); } @Test @@ -71,7 +71,7 @@ public class ContentNegotiationConfigurerTests { @Test public void addMediaTypes() throws Exception { - this.configurer.addMediaTypes(Collections.singletonMap("json", MediaType.APPLICATION_JSON)); + this.configurer.mediaTypes(Collections.singletonMap("json", MediaType.APPLICATION_JSON)); ContentNegotiationManager manager = this.configurer.getContentNegotiationManager(); this.servletRequest.setRequestURI("/flower.json"); @@ -80,9 +80,9 @@ public class ContentNegotiationConfigurerTests { @Test public void favorParameter() throws Exception { - this.configurer.setFavorParameter(true); - this.configurer.setParameterName("f"); - this.configurer.addMediaTypes(Collections.singletonMap("json", MediaType.APPLICATION_JSON)); + this.configurer.favorParameter(true); + this.configurer.parameterName("f"); + this.configurer.mediaTypes(Collections.singletonMap("json", MediaType.APPLICATION_JSON)); ContentNegotiationManager manager = this.configurer.getContentNegotiationManager(); this.servletRequest.setRequestURI("/flower"); @@ -93,7 +93,7 @@ public class ContentNegotiationConfigurerTests { @Test public void ignoreAcceptHeader() throws Exception { - this.configurer.setIgnoreAcceptHeader(true); + this.configurer.ignoreAcceptHeader(true); ContentNegotiationManager manager = this.configurer.getContentNegotiationManager(); this.servletRequest.setRequestURI("/flower"); @@ -104,7 +104,7 @@ public class ContentNegotiationConfigurerTests { @Test public void setDefaultContentType() throws Exception { - this.configurer.setDefaultContentType(MediaType.APPLICATION_JSON); + this.configurer.defaultContentType(MediaType.APPLICATION_JSON); ContentNegotiationManager manager = this.configurer.getContentNegotiationManager(); assertEquals(Arrays.asList(MediaType.APPLICATION_JSON), manager.resolveMediaTypes(this.webRequest)); diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupportExtensionTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupportExtensionTests.java index 4324cf75a1e..db628be7a9c 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupportExtensionTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupportExtensionTests.java @@ -235,7 +235,7 @@ public class WebMvcConfigurationSupportExtensionTests { @Override public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { - configurer.setFavorParameter(true).setParameterName("f"); + configurer.favorParameter(true).parameterName("f"); } @Override