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
Backport-Issue: SPR-9168
Backport-Commit: 982cb2f258
This commit is contained in:
Rossen Stoyanchev
2012-05-11 14:39:31 -04:00
parent e66bc07c37
commit 9e370208d0
7 changed files with 167 additions and 61 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
@@ -117,6 +118,9 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport
private static final UrlPathHelper urlPathHelper = new UrlPathHelper();
static {
urlPathHelper.setUrlDecode(false);
}
private int order = Ordered.HIGHEST_PRECEDENCE;
@@ -270,7 +274,7 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport
String name = viewResolvers.get(i).getClass().getName() + i;
getApplicationContext().getAutowireCapableBeanFactory().initializeBean(viewResolvers.get(i), name);
}
}
if (this.viewResolvers.isEmpty()) {
logger.warn("Did not find any ViewResolvers to delegate to; please configure them using the " +
@@ -351,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()) {
@@ -392,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;
}
/**