From 259bcd60fbbc5cdb8b230595a5004707f4c6ff23 Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Wed, 20 Oct 2021 11:47:53 +0200 Subject: [PATCH] Change deprecated MimeType specificity usages This commit changes all code that uses now deprecated methods in MimeType and MediaType. See gh-27580 --- .../accept/HeaderContentNegotiationStrategy.java | 3 ++- .../springframework/web/client/RestTemplate.java | 3 ++- .../reactive/accept/HeaderContentTypeResolver.java | 3 ++- .../reactive/function/server/RequestPredicates.java | 3 ++- .../result/HandlerResultHandlerSupport.java | 12 ++++++++---- .../condition/AbstractMediaTypeExpression.java | 13 +++++++++++-- .../result/condition/ProducesRequestCondition.java | 6 ++++-- .../condition/ProducesRequestConditionTests.java | 4 ++-- .../web/servlet/function/DefaultServerRequest.java | 11 +++++++---- .../web/servlet/function/RequestPredicates.java | 3 ++- .../mvc/condition/AbstractMediaTypeExpression.java | 12 +++++++++++- .../mvc/condition/ProducesRequestCondition.java | 6 ++++-- ...tractMessageConverterMethodArgumentResolver.java | 5 +++-- .../AbstractMessageConverterMethodProcessor.java | 10 ++++++++-- .../view/ContentNegotiatingViewResolver.java | 10 ++++++++-- .../condition/ProducesRequestConditionTests.java | 4 ++-- 16 files changed, 78 insertions(+), 30 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/web/accept/HeaderContentNegotiationStrategy.java b/spring-web/src/main/java/org/springframework/web/accept/HeaderContentNegotiationStrategy.java index 08880a61e9..9ef86aabfd 100644 --- a/spring-web/src/main/java/org/springframework/web/accept/HeaderContentNegotiationStrategy.java +++ b/spring-web/src/main/java/org/springframework/web/accept/HeaderContentNegotiationStrategy.java @@ -23,6 +23,7 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.InvalidMediaTypeException; import org.springframework.http.MediaType; import org.springframework.util.CollectionUtils; +import org.springframework.util.MimeTypeUtils; import org.springframework.web.HttpMediaTypeNotAcceptableException; import org.springframework.web.context.request.NativeWebRequest; @@ -51,7 +52,7 @@ public class HeaderContentNegotiationStrategy implements ContentNegotiationStrat List headerValues = Arrays.asList(headerValueArray); try { List mediaTypes = MediaType.parseMediaTypes(headerValues); - MediaType.sortBySpecificityAndQuality(mediaTypes); + MimeTypeUtils.sortBySpecificity(mediaTypes); return !CollectionUtils.isEmpty(mediaTypes) ? mediaTypes : MEDIA_TYPE_ALL_LIST; } catch (InvalidMediaTypeException ex) { diff --git a/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java b/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java index b38076727a..7e27ac62a7 100644 --- a/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java +++ b/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java @@ -61,6 +61,7 @@ import org.springframework.http.converter.xml.SourceHttpMessageConverter; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; +import org.springframework.util.MimeTypeUtils; import org.springframework.web.util.DefaultUriBuilderFactory; import org.springframework.web.util.DefaultUriBuilderFactory.EncodingMode; import org.springframework.web.util.UriTemplateHandler; @@ -878,8 +879,8 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat .filter(converter -> canReadResponse(this.responseType, converter)) .flatMap((HttpMessageConverter converter) -> getSupportedMediaTypes(this.responseType, converter)) .distinct() - .sorted(MediaType.SPECIFICITY_COMPARATOR) .collect(Collectors.toList()); + MimeTypeUtils.sortBySpecificity(allSupportedMediaTypes); if (logger.isDebugEnabled()) { logger.debug("Accept=" + allSupportedMediaTypes); } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/accept/HeaderContentTypeResolver.java b/spring-webflux/src/main/java/org/springframework/web/reactive/accept/HeaderContentTypeResolver.java index 88bc3ab250..b4e1d20635 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/accept/HeaderContentTypeResolver.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/accept/HeaderContentTypeResolver.java @@ -21,6 +21,7 @@ import java.util.List; import org.springframework.http.InvalidMediaTypeException; import org.springframework.http.MediaType; import org.springframework.util.CollectionUtils; +import org.springframework.util.MimeTypeUtils; import org.springframework.web.server.NotAcceptableStatusException; import org.springframework.web.server.ServerWebExchange; @@ -36,7 +37,7 @@ public class HeaderContentTypeResolver implements RequestedContentTypeResolver { public List resolveMediaTypes(ServerWebExchange exchange) throws NotAcceptableStatusException { try { List mediaTypes = exchange.getRequest().getHeaders().getAccept(); - MediaType.sortBySpecificityAndQuality(mediaTypes); + MimeTypeUtils.sortBySpecificity(mediaTypes); return (!CollectionUtils.isEmpty(mediaTypes) ? mediaTypes : MEDIA_TYPE_ALL_LIST); } catch (InvalidMediaTypeException ex) { diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RequestPredicates.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RequestPredicates.java index d2c68f6760..444d7d44a8 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RequestPredicates.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RequestPredicates.java @@ -51,6 +51,7 @@ import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.lang.NonNull; import org.springframework.lang.Nullable; import org.springframework.util.Assert; +import org.springframework.util.MimeTypeUtils; import org.springframework.util.MultiValueMap; import org.springframework.web.cors.reactive.CorsUtils; import org.springframework.web.reactive.function.BodyExtractor; @@ -630,7 +631,7 @@ public abstract class RequestPredicates { acceptedMediaTypes = Collections.singletonList(MediaType.ALL); } else { - MediaType.sortBySpecificityAndQuality(acceptedMediaTypes); + MimeTypeUtils.sortBySpecificity(acceptedMediaTypes); } return acceptedMediaTypes; } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/HandlerResultHandlerSupport.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/HandlerResultHandlerSupport.java index 22bd329528..e7a8d3da71 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/HandlerResultHandlerSupport.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/HandlerResultHandlerSupport.java @@ -18,7 +18,6 @@ package org.springframework.web.reactive.result; import java.util.ArrayList; import java.util.Arrays; -import java.util.Comparator; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; @@ -33,6 +32,7 @@ import org.springframework.core.ReactiveAdapterRegistry; import org.springframework.http.MediaType; import org.springframework.lang.Nullable; import org.springframework.util.Assert; +import org.springframework.util.MimeTypeUtils; import org.springframework.web.reactive.HandlerMapping; import org.springframework.web.reactive.HandlerResult; import org.springframework.web.reactive.accept.RequestedContentTypeResolver; @@ -141,7 +141,7 @@ public abstract class HandlerResultHandlerSupport implements Ordered { } List result = new ArrayList<>(compatibleMediaTypes); - MediaType.sortBySpecificityAndQuality(result); + MimeTypeUtils.sortBySpecificity(result); MediaType selected = null; for (MediaType mediaType : result) { @@ -183,8 +183,12 @@ public abstract class HandlerResultHandlerSupport implements Ordered { private MediaType selectMoreSpecificMediaType(MediaType acceptable, MediaType producible) { producible = producible.copyQualityValue(acceptable); - Comparator comparator = MediaType.SPECIFICITY_COMPARATOR; - return (comparator.compare(acceptable, producible) <= 0 ? acceptable : producible); + if (acceptable.isLessSpecific(producible)) { + return producible; + } + else { + return acceptable; + } } } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/condition/AbstractMediaTypeExpression.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/condition/AbstractMediaTypeExpression.java index 63a9be4239..82e8bfb9aa 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/condition/AbstractMediaTypeExpression.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/condition/AbstractMediaTypeExpression.java @@ -78,10 +78,19 @@ abstract class AbstractMediaTypeExpression implements Comparable *
  • Sort 'Accept' header media types by quality value via - * {@link MediaType#sortByQualityValue(List)} and iterate the list. + * {@link org.springframework.util.MimeTypeUtils#sortBySpecificity(List)} + * and iterate the list. *
  • Get the first index of matching media types in each "produces" * condition first matching with {@link MediaType#equals(Object)} and * then with {@link MediaType#includes(MediaType)}. *
  • If a lower index is found, the condition at that index wins. *
  • If both indexes are equal, the media types at the index are - * compared further with {@link MediaType#SPECIFICITY_COMPARATOR}. + * compared further with {@link MediaType#isMoreSpecific(MimeType)}. * *

    It is assumed that both instances have been obtained via * {@link #getMatchingCondition(ServerWebExchange)} and each instance diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/result/condition/ProducesRequestConditionTests.java b/spring-webflux/src/test/java/org/springframework/web/reactive/result/condition/ProducesRequestConditionTests.java index 3b9e7e9753..978ca9b320 100644 --- a/spring-webflux/src/test/java/org/springframework/web/reactive/result/condition/ProducesRequestConditionTests.java +++ b/spring-webflux/src/test/java/org/springframework/web/reactive/result/condition/ProducesRequestConditionTests.java @@ -206,10 +206,10 @@ public class ProducesRequestConditionTests { MockServerWebExchange exchange = MockServerWebExchange.from(get("/").header("Accept", "text/plain")); int result = condition1.compareTo(condition2, exchange); - assertThat(result < 0).as("Invalid comparison result: " + result).isTrue(); + assertThat(result).as("Invalid comparison result: " + result).isGreaterThan(0); result = condition2.compareTo(condition1, exchange); - assertThat(result > 0).as("Invalid comparison result: " + result).isTrue(); + assertThat(result).as("Invalid comparison result: " + result).isLessThan(0); } @Test diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/function/DefaultServerRequest.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/function/DefaultServerRequest.java index 81f3700dae..f09177c2af 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/function/DefaultServerRequest.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/function/DefaultServerRequest.java @@ -57,6 +57,7 @@ import org.springframework.http.server.ServletServerHttpRequest; import org.springframework.lang.Nullable; import org.springframework.util.CollectionUtils; import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MimeTypeUtils; import org.springframework.util.MultiValueMap; import org.springframework.util.ObjectUtils; import org.springframework.web.HttpMediaTypeNotSupportedException; @@ -203,10 +204,12 @@ class DefaultServerRequest implements ServerRequest { } private List getSupportedMediaTypes(Class bodyClass) { - return this.messageConverters.stream() - .flatMap(converter -> converter.getSupportedMediaTypes(bodyClass).stream()) - .sorted(MediaType.SPECIFICITY_COMPARATOR) - .collect(Collectors.toList()); + List result = new ArrayList<>(this.messageConverters.size()); + for (HttpMessageConverter converter : this.messageConverters) { + result.addAll(converter.getSupportedMediaTypes(bodyClass)); + } + MimeTypeUtils.sortBySpecificity(result); + return result; } @Override diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/function/RequestPredicates.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/function/RequestPredicates.java index d29a96271e..db160bc4b9 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/function/RequestPredicates.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/function/RequestPredicates.java @@ -53,6 +53,7 @@ import org.springframework.http.server.RequestPath; import org.springframework.lang.NonNull; import org.springframework.lang.Nullable; import org.springframework.util.Assert; +import org.springframework.util.MimeTypeUtils; import org.springframework.util.MultiValueMap; import org.springframework.web.cors.CorsUtils; import org.springframework.web.util.UriBuilder; @@ -628,7 +629,7 @@ public abstract class RequestPredicates { acceptedMediaTypes = Collections.singletonList(MediaType.ALL); } else { - MediaType.sortBySpecificityAndQuality(acceptedMediaTypes); + MimeTypeUtils.sortBySpecificity(acceptedMediaTypes); } return acceptedMediaTypes; } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/AbstractMediaTypeExpression.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/AbstractMediaTypeExpression.java index 0b3c631993..064fbb0c17 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/AbstractMediaTypeExpression.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/AbstractMediaTypeExpression.java @@ -65,7 +65,17 @@ abstract class AbstractMediaTypeExpression implements MediaTypeExpression, Compa @Override public int compareTo(AbstractMediaTypeExpression other) { - return MediaType.SPECIFICITY_COMPARATOR.compare(this.getMediaType(), other.getMediaType()); + MediaType mediaType1 = this.getMediaType(); + MediaType mediaType2 = other.getMediaType(); + if (mediaType1.isMoreSpecific(mediaType2)) { + return -1; + } + else if (mediaType1.isLessSpecific(mediaType2)) { + return 1; + } + else { + return 0; + } } @Override diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/ProducesRequestCondition.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/ProducesRequestCondition.java index b7e3aa4fed..6361a22fca 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/ProducesRequestCondition.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/ProducesRequestCondition.java @@ -27,6 +27,7 @@ import jakarta.servlet.http.HttpServletRequest; import org.springframework.http.MediaType; import org.springframework.lang.Nullable; import org.springframework.util.CollectionUtils; +import org.springframework.util.MimeType; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import org.springframework.web.HttpMediaTypeException; @@ -238,13 +239,14 @@ public final class ProducesRequestCondition extends AbstractRequestCondition *

  • Sort 'Accept' header media types by quality value via - * {@link MediaType#sortByQualityValue(List)} and iterate the list. + * {@link org.springframework.util.MimeTypeUtils#sortBySpecificity(List)} + * and iterate the list. *
  • Get the first index of matching media types in each "produces" * condition first matching with {@link MediaType#equals(Object)} and * then with {@link MediaType#includes(MediaType)}. *
  • If a lower index is found, the condition at that index wins. *
  • If both indexes are equal, the media types at the index are - * compared further with {@link MediaType#SPECIFICITY_COMPARATOR}. + * compared further with {@link MediaType#isMoreSpecific(MimeType)}. * *

    It is assumed that both instances have been obtained via * {@link #getMatchingCondition(HttpServletRequest)} and each instance diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodArgumentResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodArgumentResolver.java index b9bf4a176b..f550766908 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodArgumentResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodArgumentResolver.java @@ -48,6 +48,7 @@ import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.http.server.ServletServerHttpRequest; import org.springframework.lang.Nullable; import org.springframework.util.Assert; +import org.springframework.util.MimeTypeUtils; import org.springframework.util.StreamUtils; import org.springframework.validation.Errors; import org.springframework.validation.annotation.ValidationAnnotationUtils; @@ -263,7 +264,7 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements /** * Return the media types supported by all provided message converters sorted - * by specificity via {@link MediaType#sortBySpecificity(List)}. + * by specificity via {@link MimeTypeUtils#sortBySpecificity(List)}. * @since 5.3.4 */ protected List getSupportedMediaTypes(Class clazz) { @@ -272,7 +273,7 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements mediaTypeSet.addAll(converter.getSupportedMediaTypes(clazz)); } List result = new ArrayList<>(mediaTypeSet); - MediaType.sortBySpecificity(result); + MimeTypeUtils.sortBySpecificity(result); return result; } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodProcessor.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodProcessor.java index bd18540925..23bb651e20 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodProcessor.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodProcessor.java @@ -53,6 +53,7 @@ import org.springframework.http.server.ServletServerHttpResponse; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; +import org.springframework.util.MimeTypeUtils; import org.springframework.util.StringUtils; import org.springframework.web.HttpMediaTypeNotAcceptableException; import org.springframework.web.accept.ContentNegotiationManager; @@ -251,7 +252,7 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe return; } - MediaType.sortBySpecificityAndQuality(mediaTypesToUse); + MimeTypeUtils.sortBySpecificity(mediaTypesToUse); for (MediaType mediaType : mediaTypesToUse) { if (mediaType.isConcrete()) { @@ -400,7 +401,12 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe */ private MediaType getMostSpecificMediaType(MediaType acceptType, MediaType produceType) { MediaType produceTypeToUse = produceType.copyQualityValue(acceptType); - return (MediaType.SPECIFICITY_COMPARATOR.compare(acceptType, produceTypeToUse) <= 0 ? acceptType : produceTypeToUse); + if (acceptType.isLessSpecific(produceTypeToUse)) { + return produceTypeToUse; + } + else { + return acceptType; + } } /** 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 4fdb0a2c88..9f1c2d3b20 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 @@ -37,6 +37,7 @@ import org.springframework.http.MediaType; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; +import org.springframework.util.MimeTypeUtils; import org.springframework.util.StringUtils; import org.springframework.web.HttpMediaTypeNotAcceptableException; import org.springframework.web.accept.ContentNegotiationManager; @@ -268,7 +269,7 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport } } List selectedMediaTypes = new ArrayList<>(compatibleMediaTypes); - MediaType.sortBySpecificityAndQuality(selectedMediaTypes); + MimeTypeUtils.sortBySpecificity(selectedMediaTypes); return selectedMediaTypes; } catch (HttpMediaTypeNotAcceptableException ex) { @@ -297,7 +298,12 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport */ private MediaType getMostSpecificMediaType(MediaType acceptType, MediaType produceType) { produceType = produceType.copyQualityValue(acceptType); - return (MediaType.SPECIFICITY_COMPARATOR.compare(acceptType, produceType) < 0 ? acceptType : produceType); + if (acceptType.isLessSpecific(produceType)) { + return produceType; + } + else { + return acceptType; + } } private List getCandidateViews(String viewName, Locale locale, List requestedMediaTypes) diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/condition/ProducesRequestConditionTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/condition/ProducesRequestConditionTests.java index 15244e1baa..1f8850e49b 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/condition/ProducesRequestConditionTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/condition/ProducesRequestConditionTests.java @@ -221,10 +221,10 @@ public class ProducesRequestConditionTests { HttpServletRequest request = createRequest("text/plain"); int result = condition1.compareTo(condition2, request); - assertThat(result < 0).as("Invalid comparison result: " + result).isTrue(); + assertThat(result).as("Invalid comparison result: " + result).isGreaterThan(0); result = condition2.compareTo(condition1, request); - assertThat(result > 0).as("Invalid comparison result: " + result).isTrue(); + assertThat(result).as("Invalid comparison result: " + result).isLessThan(0); } @Test