Fix content negotiation issue with sort by q-value

Before this fix the q-value of media types in the Accept header were
ignored when using the new RequestMappingHandlerAdapter in combination
with @ResponseBody and HttpMessageConverters.

Issue: SPR-9160
This commit is contained in:
Rossen Stoyanchev
2012-05-11 14:39:31 -04:00
parent 75578d4e88
commit 982cb2f258
7 changed files with 148 additions and 55 deletions

View File

@@ -21,7 +21,6 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
@@ -117,7 +116,7 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
}
List<MediaType> mediaTypes = new ArrayList<MediaType>(compatibleMediaTypes);
MediaType.sortBySpecificity(mediaTypes);
MediaType.sortBySpecificityAndQuality(mediaTypes);
MediaType selectedMediaType = null;
for (MediaType mediaType : mediaTypes) {
@@ -131,6 +130,8 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
}
}
selectedMediaType = selectedMediaType.removeQualityValue();
if (selectedMediaType != null) {
for (HttpMessageConverter<?> messageConverter : messageConverters) {
if (messageConverter.canWrite(returnValueClass, selectedMediaType)) {
@@ -188,14 +189,12 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
}
/**
* Returns the more specific media type using the q-value of the first media type for both.
* Return the more specific of the acceptable and the producible media types
* with the q-value of the former.
*/
private MediaType getMostSpecificMediaType(MediaType type1, MediaType type2) {
double quality = type1.getQualityValue();
Map<String, String> params = Collections.singletonMap("q", String.valueOf(quality));
MediaType t1 = new MediaType(type1, params);
MediaType t2 = new MediaType(type2, params);
return MediaType.SPECIFICITY_COMPARATOR.compare(t1, t2) <= 0 ? type1 : type2;
private MediaType getMostSpecificMediaType(MediaType acceptType, MediaType produceType) {
produceType = produceType.copyQualityValue(acceptType);
return MediaType.SPECIFICITY_COMPARATOR.compare(acceptType, produceType) < 0 ? acceptType : produceType;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* 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.
@@ -101,6 +101,7 @@ import org.springframework.web.util.WebUtils;
*
* @author Arjen Poutsma
* @author Juergen Hoeller
* @author Rossen Stoyanchev
* @since 3.0
* @see ViewResolver
* @see InternalResourceViewResolver
@@ -354,13 +355,13 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport
}
}
}
List<MediaType> mediaTypes = new ArrayList<MediaType>(compatibleMediaTypes);
MediaType.sortByQualityValue(mediaTypes);
List<MediaType> selectedMediaTypes = new ArrayList<MediaType>(compatibleMediaTypes);
MediaType.sortBySpecificityAndQuality(selectedMediaTypes);
if (logger.isDebugEnabled()) {
logger.debug("Requested media types are " + mediaTypes + " based on Accept header types " +
logger.debug("Requested media types are " + selectedMediaTypes + " based on Accept header types " +
"and producible media types " + producibleMediaTypes + ")");
}
return mediaTypes;
return selectedMediaTypes;
}
catch (IllegalArgumentException ex) {
if (logger.isDebugEnabled()) {
@@ -395,14 +396,12 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport
}
/**
* Returns the more specific media type using the q-value of the first media type for both.
* Return the more specific of the acceptable and the producible media types
* with the q-value of the former.
*/
private MediaType getMostSpecificMediaType(MediaType type1, MediaType type2) {
double quality = type1.getQualityValue();
Map<String, String> params = Collections.singletonMap("q", String.valueOf(quality));
MediaType t1 = new MediaType(type1, params);
MediaType t2 = new MediaType(type2, params);
return MediaType.SPECIFICITY_COMPARATOR.compare(t1, t2) <= 0 ? type1 : type2;
private MediaType getMostSpecificMediaType(MediaType acceptType, MediaType produceType) {
produceType = produceType.copyQualityValue(acceptType);
return MediaType.SPECIFICITY_COMPARATOR.compare(acceptType, produceType) < 0 ? acceptType : produceType;
}
/**