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 b05cbd7f97b..8cf79f927d4 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 @@ -20,6 +20,7 @@ import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Map.Entry; import java.util.Properties; import javax.servlet.ServletContext; @@ -52,7 +53,7 @@ public class ContentNegotiationManagerFactoryBean private boolean ignoreAcceptHeader = false; - private Properties mediaTypes = new Properties(); + private Map mediaTypes = new HashMap(); private Boolean useJaf; @@ -64,7 +65,6 @@ public class ContentNegotiationManagerFactoryBean private ServletContext servletContext; - /** * Indicate whether the extension of the request path should be used to determine * the requested media type with the highest priority. @@ -77,21 +77,43 @@ public class ContentNegotiationManagerFactoryBean } /** - * 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)}. + * Add mappings from file extensions to media types represented as strings. + *

When this mapping is not set or when an extension is not found, the Java + * Action Framework, if available, may be used if enabled via + * {@link #setFavorPathExtension(boolean)}. + * + * @see #addMediaType(String, MediaType) + * @see #addMediaTypes(Map) */ public void setMediaTypes(Properties mediaTypes) { if (!CollectionUtils.isEmpty(mediaTypes)) { - for (Map.Entry entry : mediaTypes.entrySet()) { - String extension = ((String) entry.getKey()).toLowerCase(Locale.ENGLISH); + for (Entry entry : mediaTypes.entrySet()) { + String extension = ((String)entry.getKey()).toLowerCase(Locale.ENGLISH); this.mediaTypes.put(extension, MediaType.valueOf((String) entry.getValue())); } } } - public Properties getMediaTypes() { - return this.mediaTypes; + /** + * Add a mapping from a file extension to a media type. + *

If no mapping is added or when an extension is not found, the Java + * Action Framework, if available, may be used if enabled via + * {@link #setFavorPathExtension(boolean)}. + */ + public void addMediaType(String fileExtension, MediaType mediaType) { + this.mediaTypes.put(fileExtension, mediaType); + } + + /** + * Add mappings from file extensions to media types. + *

If no mappings are added or when an extension is not found, the Java + * Action Framework, if available, may be used if enabled via + * {@link #setFavorPathExtension(boolean)}. + */ + public void addMediaTypes(Map mediaTypes) { + if (mediaTypes != null) { + this.mediaTypes.putAll(mediaTypes); + } } /** @@ -99,6 +121,7 @@ public class ContentNegotiationManagerFactoryBean * 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(Properties) */ @@ -115,6 +138,7 @@ public class ContentNegotiationManagerFactoryBean * {@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(Properties)}. + * * @see #setParameterName(String) */ public void setFavorParameter(boolean favorParameter) { @@ -145,8 +169,8 @@ public class ContentNegotiationManagerFactoryBean /** * 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. + * nor a request parameter, nor the {@code Accept} header could help + * determine the requested content type. */ public void setDefaultContentType(MediaType defaultContentType) { this.defaultContentType = defaultContentType; @@ -159,16 +183,12 @@ public class ContentNegotiationManagerFactoryBean public void afterPropertiesSet() throws Exception { List strategies = new ArrayList(); - Map mediaTypesMap = new HashMap(); - CollectionUtils.mergePropertiesIntoMap(this.mediaTypes, mediaTypesMap); - if (this.favorPathExtension) { PathExtensionContentNegotiationStrategy strategy; if (this.servletContext != null) { - strategy = new ServletPathExtensionContentNegotiationStrategy(this.servletContext, mediaTypesMap); - } - else { - strategy = new PathExtensionContentNegotiationStrategy(mediaTypesMap); + strategy = new ServletPathExtensionContentNegotiationStrategy(this.servletContext, this.mediaTypes); + } else { + strategy = new PathExtensionContentNegotiationStrategy(this.mediaTypes); } if (this.useJaf != null) { strategy.setUseJaf(this.useJaf); @@ -177,7 +197,7 @@ public class ContentNegotiationManagerFactoryBean } if (this.favorParameter) { - ParameterContentNegotiationStrategy strategy = new ParameterContentNegotiationStrategy(mediaTypesMap); + ParameterContentNegotiationStrategy strategy = new ParameterContentNegotiationStrategy(this.mediaTypes); strategy.setParameterName(this.parameterName); strategies.add(strategy); } 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 4d82e3f4459..d086093402c 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 @@ -19,7 +19,8 @@ import static org.junit.Assert.assertEquals; import java.util.Arrays; import java.util.Collections; -import java.util.Properties; +import java.util.HashMap; +import java.util.Map; import org.junit.Before; import org.junit.Test; @@ -74,9 +75,9 @@ public class ContentNegotiationManagerFactoryBeanTests { @Test public void addMediaTypes() throws Exception { - Properties mediaTypes = new Properties(); - mediaTypes.put("json", MediaType.APPLICATION_JSON_VALUE); - this.factoryBean.setMediaTypes(mediaTypes); + Map mediaTypes = new HashMap(); + mediaTypes.put("json", MediaType.APPLICATION_JSON); + this.factoryBean.addMediaTypes(mediaTypes); this.factoryBean.afterPropertiesSet(); ContentNegotiationManager manager = this.factoryBean.getObject(); @@ -89,9 +90,9 @@ public class ContentNegotiationManagerFactoryBeanTests { public void favorParameter() throws Exception { this.factoryBean.setFavorParameter(true); - Properties mediaTypes = new Properties(); - mediaTypes.put("json", MediaType.APPLICATION_JSON_VALUE); - this.factoryBean.setMediaTypes(mediaTypes); + Map mediaTypes = new HashMap(); + mediaTypes.put("json", MediaType.APPLICATION_JSON); + this.factoryBean.addMediaTypes(mediaTypes); this.factoryBean.afterPropertiesSet(); ContentNegotiationManager manager = this.factoryBean.getObject(); 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 9900bc32a79..7073e7122a3 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,6 +15,7 @@ */ package org.springframework.web.servlet.config.annotation; +import java.util.HashMap; import java.util.Map; import javax.servlet.ServletContext; @@ -36,7 +37,9 @@ import org.springframework.web.accept.ContentNegotiationManagerFactoryBean; */ public class ContentNegotiationConfigurer { - private ContentNegotiationManagerFactoryBean factoryBean = new ContentNegotiationManagerFactoryBean(); + private final ContentNegotiationManagerFactoryBean factoryBean = new ContentNegotiationManagerFactoryBean(); + + private final Map mediaTypes = new HashMap(); /** @@ -64,7 +67,7 @@ public class ContentNegotiationConfigurer { * still be used in conjunction with {@link #favorPathExtension(boolean)}. */ public ContentNegotiationConfigurer mediaType(String extension, MediaType mediaType) { - this.factoryBean.getMediaTypes().put(extension, mediaType); + this.mediaTypes.put(extension, mediaType); return this; } @@ -75,7 +78,7 @@ public class ContentNegotiationConfigurer { */ public ContentNegotiationConfigurer mediaTypes(Map mediaTypes) { if (mediaTypes != null) { - this.factoryBean.getMediaTypes().putAll(mediaTypes); + this.mediaTypes.putAll(mediaTypes); } return this; } @@ -86,7 +89,7 @@ public class ContentNegotiationConfigurer { * still be used in conjunction with {@link #favorPathExtension(boolean)}. */ public ContentNegotiationConfigurer replaceMediaTypes(Map mediaTypes) { - this.factoryBean.getMediaTypes().clear(); + this.mediaTypes.clear(); mediaTypes(mediaTypes); return this; } @@ -157,6 +160,9 @@ public class ContentNegotiationConfigurer { * Return the configured {@link ContentNegotiationManager} instance */ protected ContentNegotiationManager getContentNegotiationManager() throws Exception { + if (!this.mediaTypes.isEmpty()) { + this.factoryBean.addMediaTypes(mediaTypes); + } this.factoryBean.afterPropertiesSet(); return this.factoryBean.getObject(); } 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 cc497262972..2d543941af6 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 @@ -23,6 +23,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Properties; import java.util.Set; import javax.activation.FileTypeMap; @@ -196,7 +197,9 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport @Deprecated public void setMediaTypes(Map mediaTypes) { if (mediaTypes != null) { - this.cnManagerFactoryBean.getMediaTypes().putAll(mediaTypes); + Properties props = new Properties(); + props.putAll(mediaTypes); + this.cnManagerFactoryBean.setMediaTypes(props); } }