Fix ClassCastException when setting media types

Issue: SPR-10019
This commit is contained in:
Rossen Stoyanchev 2013-01-03 15:13:19 -05:00
parent 42cdb200ed
commit 9f9f1ed253
4 changed files with 61 additions and 31 deletions

View File

@ -20,6 +20,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties; import java.util.Properties;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
@ -52,7 +53,7 @@ public class ContentNegotiationManagerFactoryBean
private boolean ignoreAcceptHeader = false; private boolean ignoreAcceptHeader = false;
private Properties mediaTypes = new Properties(); private Map<String, MediaType> mediaTypes = new HashMap<String, MediaType>();
private Boolean useJaf; private Boolean useJaf;
@ -64,7 +65,6 @@ public class ContentNegotiationManagerFactoryBean
private ServletContext servletContext; private ServletContext servletContext;
/** /**
* Indicate whether the extension of the request path should be used to determine * Indicate whether the extension of the request path should be used to determine
* the requested media type with the <em>highest priority</em>. * the requested media type with the <em>highest priority</em>.
@ -77,21 +77,43 @@ public class ContentNegotiationManagerFactoryBean
} }
/** /**
* Add mappings from file extensions to media types. * Add mappings from file extensions to media types represented as strings.
* <p>If this property is not set, the Java Action Framework, if available, may * <p>When this mapping is not set or when an extension is not found, the Java
* still be used in conjunction with {@link #setFavorPathExtension(boolean)}. * 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) { public void setMediaTypes(Properties mediaTypes) {
if (!CollectionUtils.isEmpty(mediaTypes)) { if (!CollectionUtils.isEmpty(mediaTypes)) {
for (Map.Entry<Object, Object> entry : mediaTypes.entrySet()) { for (Entry<Object, Object> entry : mediaTypes.entrySet()) {
String extension = ((String) entry.getKey()).toLowerCase(Locale.ENGLISH); String extension = ((String)entry.getKey()).toLowerCase(Locale.ENGLISH);
this.mediaTypes.put(extension, MediaType.valueOf((String) entry.getValue())); 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.
* <p>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.
* <p>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<String, MediaType> 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 * to map from file extensions to media types. This is used only when
* {@link #setFavorPathExtension(boolean)} is set to {@code true}. * {@link #setFavorPathExtension(boolean)} is set to {@code true}.
* <p>The default value is {@code true}. * <p>The default value is {@code true}.
*
* @see #parameterName * @see #parameterName
* @see #setMediaTypes(Properties) * @see #setMediaTypes(Properties)
*/ */
@ -115,6 +138,7 @@ public class ContentNegotiationManagerFactoryBean
* {@code "application/pdf"} regardless of the {@code Accept} header. * {@code "application/pdf"} regardless of the {@code Accept} header.
* <p>To use this option effectively you must also configure the MediaType * <p>To use this option effectively you must also configure the MediaType
* type mappings via {@link #setMediaTypes(Properties)}. * type mappings via {@link #setMediaTypes(Properties)}.
*
* @see #setParameterName(String) * @see #setParameterName(String)
*/ */
public void setFavorParameter(boolean favorParameter) { public void setFavorParameter(boolean favorParameter) {
@ -145,8 +169,8 @@ public class ContentNegotiationManagerFactoryBean
/** /**
* Set the default content type. * Set the default content type.
* <p>This content type will be used when neither the request path extension, * <p>This content type will be used when neither the request path extension,
* nor a request parameter, nor the {@code Accept} header could help determine * nor a request parameter, nor the {@code Accept} header could help
* the requested content type. * determine the requested content type.
*/ */
public void setDefaultContentType(MediaType defaultContentType) { public void setDefaultContentType(MediaType defaultContentType) {
this.defaultContentType = defaultContentType; this.defaultContentType = defaultContentType;
@ -159,16 +183,12 @@ public class ContentNegotiationManagerFactoryBean
public void afterPropertiesSet() throws Exception { public void afterPropertiesSet() throws Exception {
List<ContentNegotiationStrategy> strategies = new ArrayList<ContentNegotiationStrategy>(); List<ContentNegotiationStrategy> strategies = new ArrayList<ContentNegotiationStrategy>();
Map<String, MediaType> mediaTypesMap = new HashMap<String, MediaType>();
CollectionUtils.mergePropertiesIntoMap(this.mediaTypes, mediaTypesMap);
if (this.favorPathExtension) { if (this.favorPathExtension) {
PathExtensionContentNegotiationStrategy strategy; PathExtensionContentNegotiationStrategy strategy;
if (this.servletContext != null) { if (this.servletContext != null) {
strategy = new ServletPathExtensionContentNegotiationStrategy(this.servletContext, mediaTypesMap); strategy = new ServletPathExtensionContentNegotiationStrategy(this.servletContext, this.mediaTypes);
} } else {
else { strategy = new PathExtensionContentNegotiationStrategy(this.mediaTypes);
strategy = new PathExtensionContentNegotiationStrategy(mediaTypesMap);
} }
if (this.useJaf != null) { if (this.useJaf != null) {
strategy.setUseJaf(this.useJaf); strategy.setUseJaf(this.useJaf);
@ -177,7 +197,7 @@ public class ContentNegotiationManagerFactoryBean
} }
if (this.favorParameter) { if (this.favorParameter) {
ParameterContentNegotiationStrategy strategy = new ParameterContentNegotiationStrategy(mediaTypesMap); ParameterContentNegotiationStrategy strategy = new ParameterContentNegotiationStrategy(this.mediaTypes);
strategy.setParameterName(this.parameterName); strategy.setParameterName(this.parameterName);
strategies.add(strategy); strategies.add(strategy);
} }

View File

@ -19,7 +19,8 @@ import static org.junit.Assert.assertEquals;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Properties; import java.util.HashMap;
import java.util.Map;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -74,9 +75,9 @@ public class ContentNegotiationManagerFactoryBeanTests {
@Test @Test
public void addMediaTypes() throws Exception { public void addMediaTypes() throws Exception {
Properties mediaTypes = new Properties(); Map<String, MediaType> mediaTypes = new HashMap<String, MediaType>();
mediaTypes.put("json", MediaType.APPLICATION_JSON_VALUE); mediaTypes.put("json", MediaType.APPLICATION_JSON);
this.factoryBean.setMediaTypes(mediaTypes); this.factoryBean.addMediaTypes(mediaTypes);
this.factoryBean.afterPropertiesSet(); this.factoryBean.afterPropertiesSet();
ContentNegotiationManager manager = this.factoryBean.getObject(); ContentNegotiationManager manager = this.factoryBean.getObject();
@ -89,9 +90,9 @@ public class ContentNegotiationManagerFactoryBeanTests {
public void favorParameter() throws Exception { public void favorParameter() throws Exception {
this.factoryBean.setFavorParameter(true); this.factoryBean.setFavorParameter(true);
Properties mediaTypes = new Properties(); Map<String, MediaType> mediaTypes = new HashMap<String, MediaType>();
mediaTypes.put("json", MediaType.APPLICATION_JSON_VALUE); mediaTypes.put("json", MediaType.APPLICATION_JSON);
this.factoryBean.setMediaTypes(mediaTypes); this.factoryBean.addMediaTypes(mediaTypes);
this.factoryBean.afterPropertiesSet(); this.factoryBean.afterPropertiesSet();
ContentNegotiationManager manager = this.factoryBean.getObject(); ContentNegotiationManager manager = this.factoryBean.getObject();

View File

@ -15,6 +15,7 @@
*/ */
package org.springframework.web.servlet.config.annotation; package org.springframework.web.servlet.config.annotation;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
@ -36,7 +37,9 @@ import org.springframework.web.accept.ContentNegotiationManagerFactoryBean;
*/ */
public class ContentNegotiationConfigurer { public class ContentNegotiationConfigurer {
private ContentNegotiationManagerFactoryBean factoryBean = new ContentNegotiationManagerFactoryBean(); private final ContentNegotiationManagerFactoryBean factoryBean = new ContentNegotiationManagerFactoryBean();
private final Map<String, MediaType> mediaTypes = new HashMap<String, MediaType>();
/** /**
@ -64,7 +67,7 @@ public class ContentNegotiationConfigurer {
* still be used in conjunction with {@link #favorPathExtension(boolean)}. * still be used in conjunction with {@link #favorPathExtension(boolean)}.
*/ */
public ContentNegotiationConfigurer mediaType(String extension, MediaType mediaType) { public ContentNegotiationConfigurer mediaType(String extension, MediaType mediaType) {
this.factoryBean.getMediaTypes().put(extension, mediaType); this.mediaTypes.put(extension, mediaType);
return this; return this;
} }
@ -75,7 +78,7 @@ public class ContentNegotiationConfigurer {
*/ */
public ContentNegotiationConfigurer mediaTypes(Map<String, MediaType> mediaTypes) { public ContentNegotiationConfigurer mediaTypes(Map<String, MediaType> mediaTypes) {
if (mediaTypes != null) { if (mediaTypes != null) {
this.factoryBean.getMediaTypes().putAll(mediaTypes); this.mediaTypes.putAll(mediaTypes);
} }
return this; return this;
} }
@ -86,7 +89,7 @@ public class ContentNegotiationConfigurer {
* still be used in conjunction with {@link #favorPathExtension(boolean)}. * still be used in conjunction with {@link #favorPathExtension(boolean)}.
*/ */
public ContentNegotiationConfigurer replaceMediaTypes(Map<String, MediaType> mediaTypes) { public ContentNegotiationConfigurer replaceMediaTypes(Map<String, MediaType> mediaTypes) {
this.factoryBean.getMediaTypes().clear(); this.mediaTypes.clear();
mediaTypes(mediaTypes); mediaTypes(mediaTypes);
return this; return this;
} }
@ -157,6 +160,9 @@ public class ContentNegotiationConfigurer {
* Return the configured {@link ContentNegotiationManager} instance * Return the configured {@link ContentNegotiationManager} instance
*/ */
protected ContentNegotiationManager getContentNegotiationManager() throws Exception { protected ContentNegotiationManager getContentNegotiationManager() throws Exception {
if (!this.mediaTypes.isEmpty()) {
this.factoryBean.addMediaTypes(mediaTypes);
}
this.factoryBean.afterPropertiesSet(); this.factoryBean.afterPropertiesSet();
return this.factoryBean.getObject(); return this.factoryBean.getObject();
} }

View File

@ -23,6 +23,7 @@ import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Properties;
import java.util.Set; import java.util.Set;
import javax.activation.FileTypeMap; import javax.activation.FileTypeMap;
@ -196,7 +197,9 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport
@Deprecated @Deprecated
public void setMediaTypes(Map<String, String> mediaTypes) { public void setMediaTypes(Map<String, String> mediaTypes) {
if (mediaTypes != null) { if (mediaTypes != null) {
this.cnManagerFactoryBean.getMediaTypes().putAll(mediaTypes); Properties props = new Properties();
props.putAll(mediaTypes);
this.cnManagerFactoryBean.setMediaTypes(props);
} }
} }