Refine ContentNegotiationStrategy contract
Consistently return "*/*" if no media types were requested rather than an empty list. Existing code has to check for both in any case to see if nothing was requested. Issue: SPR-16624
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -122,7 +122,7 @@ public abstract class AbstractMappingContentNegotiationStrategy extends MappingM
|
||||
return Collections.singletonList(mediaType);
|
||||
}
|
||||
}
|
||||
return Collections.emptyList();
|
||||
return MEDIA_TYPE_ALL_LIST;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -45,9 +45,6 @@ import org.springframework.web.context.request.NativeWebRequest;
|
||||
*/
|
||||
public class ContentNegotiationManager implements ContentNegotiationStrategy, MediaTypeFileExtensionResolver {
|
||||
|
||||
private static final List<MediaType> MEDIA_TYPE_ALL = Collections.singletonList(MediaType.ALL);
|
||||
|
||||
|
||||
private final List<ContentNegotiationStrategy> strategies = new ArrayList<>();
|
||||
|
||||
private final Set<MediaTypeFileExtensionResolver> resolvers = new LinkedHashSet<>();
|
||||
@@ -125,12 +122,12 @@ public class ContentNegotiationManager implements ContentNegotiationStrategy, Me
|
||||
public List<MediaType> resolveMediaTypes(NativeWebRequest request) throws HttpMediaTypeNotAcceptableException {
|
||||
for (ContentNegotiationStrategy strategy : this.strategies) {
|
||||
List<MediaType> mediaTypes = strategy.resolveMediaTypes(request);
|
||||
if (mediaTypes.isEmpty() || mediaTypes.equals(MEDIA_TYPE_ALL)) {
|
||||
if (mediaTypes.equals(MEDIA_TYPE_ALL_LIST)) {
|
||||
continue;
|
||||
}
|
||||
return mediaTypes;
|
||||
}
|
||||
return Collections.emptyList();
|
||||
return MEDIA_TYPE_ALL_LIST;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.web.accept;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
@@ -31,11 +32,20 @@ import org.springframework.web.context.request.NativeWebRequest;
|
||||
@FunctionalInterface
|
||||
public interface ContentNegotiationStrategy {
|
||||
|
||||
/**
|
||||
* A singleton list with {@link MediaType#ALL} that is returned from
|
||||
* {@link #resolveMediaTypes} when no specific media types are requested.
|
||||
* @since 5.0.5
|
||||
*/
|
||||
List<MediaType> MEDIA_TYPE_ALL_LIST = Collections.singletonList(MediaType.ALL);
|
||||
|
||||
|
||||
/**
|
||||
* Resolve the given request to a list of media types. The returned list is
|
||||
* ordered by specificity first and by quality parameter second.
|
||||
* @param webRequest the current request
|
||||
* @return the requested media types or an empty list (never {@code null})
|
||||
* @return the requested media types, or {@link #MEDIA_TYPE_ALL_LIST} if none
|
||||
* were requested.
|
||||
* @throws HttpMediaTypeNotAcceptableException if the requested media
|
||||
* types cannot be parsed
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -17,12 +17,12 @@
|
||||
package org.springframework.web.accept;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.InvalidMediaTypeException;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.HttpMediaTypeNotAcceptableException;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
|
||||
@@ -45,14 +45,14 @@ public class HeaderContentNegotiationStrategy implements ContentNegotiationStrat
|
||||
|
||||
String[] headerValueArray = request.getHeaderValues(HttpHeaders.ACCEPT);
|
||||
if (headerValueArray == null) {
|
||||
return Collections.emptyList();
|
||||
return MEDIA_TYPE_ALL_LIST;
|
||||
}
|
||||
|
||||
List<String> headerValues = Arrays.asList(headerValueArray);
|
||||
try {
|
||||
List<MediaType> mediaTypes = MediaType.parseMediaTypes(headerValues);
|
||||
MediaType.sortBySpecificityAndQuality(mediaTypes);
|
||||
return mediaTypes;
|
||||
return !CollectionUtils.isEmpty(mediaTypes) ? mediaTypes : MEDIA_TYPE_ALL_LIST;
|
||||
}
|
||||
catch (InvalidMediaTypeException ex) {
|
||||
throw new HttpMediaTypeNotAcceptableException(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -24,6 +24,7 @@ import java.util.Map;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.test.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.test.MockServletContext;
|
||||
@@ -32,7 +33,7 @@ import org.springframework.web.HttpMediaTypeNotAcceptableException;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.context.request.ServletWebRequest;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Test fixture for {@link ContentNegotiationManagerFactoryBean} tests.
|
||||
@@ -74,13 +75,13 @@ public class ContentNegotiationManagerFactoryBeanTests {
|
||||
this.servletRequest.setRequestURI("/flower.foobarbaz");
|
||||
|
||||
assertEquals("Should ignore unknown extensions by default",
|
||||
Collections.<MediaType>emptyList(), manager.resolveMediaTypes(this.webRequest));
|
||||
ContentNegotiationStrategy.MEDIA_TYPE_ALL_LIST, manager.resolveMediaTypes(this.webRequest));
|
||||
|
||||
this.servletRequest.setRequestURI("/flower");
|
||||
this.servletRequest.setParameter("format", "gif");
|
||||
|
||||
assertEquals("Should not resolve request parameters by default",
|
||||
Collections.<MediaType>emptyList(), manager.resolveMediaTypes(this.webRequest));
|
||||
ContentNegotiationStrategy.MEDIA_TYPE_ALL_LIST, manager.resolveMediaTypes(this.webRequest));
|
||||
|
||||
this.servletRequest.setRequestURI("/flower");
|
||||
this.servletRequest.addHeader("Accept", MediaType.IMAGE_GIF_VALUE);
|
||||
@@ -179,7 +180,7 @@ public class ContentNegotiationManagerFactoryBeanTests {
|
||||
this.servletRequest.setRequestURI("/flower");
|
||||
this.servletRequest.addHeader("Accept", MediaType.IMAGE_GIF_VALUE);
|
||||
|
||||
assertEquals(Collections.<MediaType>emptyList(), manager.resolveMediaTypes(this.webRequest));
|
||||
assertEquals(ContentNegotiationStrategy.MEDIA_TYPE_ALL_LIST, manager.resolveMediaTypes(this.webRequest));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -53,7 +53,7 @@ public class MappingContentNegotiationStrategyTests {
|
||||
|
||||
List<MediaType> mediaTypes = strategy.resolveMediaTypes(null);
|
||||
|
||||
assertEquals(0, mediaTypes.size());
|
||||
assertEquals(ContentNegotiationStrategy.MEDIA_TYPE_ALL_LIST, mediaTypes);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -63,7 +63,7 @@ public class MappingContentNegotiationStrategyTests {
|
||||
|
||||
List<MediaType> mediaTypes = strategy.resolveMediaTypes(null);
|
||||
|
||||
assertEquals(0, mediaTypes.size());
|
||||
assertEquals(ContentNegotiationStrategy.MEDIA_TYPE_ALL_LIST, mediaTypes);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -29,8 +29,7 @@ import org.springframework.web.HttpMediaTypeNotAcceptableException;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.context.request.ServletWebRequest;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* A test fixture for PathExtensionContentNegotiationStrategy.
|
||||
@@ -89,10 +88,12 @@ public class PathExtensionContentNegotiationStrategyTests {
|
||||
|
||||
this.servletRequest.setContextPath("/project-1.0.0.M3");
|
||||
this.servletRequest.setRequestURI("/project-1.0.0.M3/");
|
||||
assertTrue("Context path should be excluded", strategy.resolveMediaTypes(webRequest).isEmpty());
|
||||
assertEquals("Context path should be excluded", ContentNegotiationStrategy.MEDIA_TYPE_ALL_LIST,
|
||||
strategy.resolveMediaTypes(webRequest));
|
||||
|
||||
this.servletRequest.setRequestURI("/project-1.0.0.M3");
|
||||
assertTrue("Context path should be excluded", strategy.resolveMediaTypes(webRequest).isEmpty());
|
||||
assertEquals("Context path should be excluded", ContentNegotiationStrategy.MEDIA_TYPE_ALL_LIST,
|
||||
strategy.resolveMediaTypes(webRequest));
|
||||
}
|
||||
|
||||
// SPR-9390
|
||||
@@ -118,7 +119,7 @@ public class PathExtensionContentNegotiationStrategyTests {
|
||||
PathExtensionContentNegotiationStrategy strategy = new PathExtensionContentNegotiationStrategy();
|
||||
List<MediaType> mediaTypes = strategy.resolveMediaTypes(this.webRequest);
|
||||
|
||||
assertEquals(Collections.<MediaType>emptyList(), mediaTypes);
|
||||
assertEquals(ContentNegotiationStrategy.MEDIA_TYPE_ALL_LIST, mediaTypes);
|
||||
}
|
||||
|
||||
@Test(expected = HttpMediaTypeNotAcceptableException.class)
|
||||
|
||||
@@ -259,8 +259,7 @@ public final class ProducesRequestCondition extends AbstractRequestCondition<Pro
|
||||
}
|
||||
|
||||
private List<MediaType> getAcceptedMediaTypes(HttpServletRequest request) throws HttpMediaTypeNotAcceptableException {
|
||||
List<MediaType> mediaTypes = this.contentNegotiationManager.resolveMediaTypes(new ServletWebRequest(request));
|
||||
return mediaTypes.isEmpty() ? Collections.singletonList(MediaType.ALL) : mediaTypes;
|
||||
return this.contentNegotiationManager.resolveMediaTypes(new ServletWebRequest(request));
|
||||
}
|
||||
|
||||
private int indexOfEqualMediaType(MediaType mediaType) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -365,8 +365,7 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
|
||||
private List<MediaType> getAcceptableMediaTypes(HttpServletRequest request)
|
||||
throws HttpMediaTypeNotAcceptableException {
|
||||
|
||||
List<MediaType> types = this.contentNegotiationManager.resolveMediaTypes(new ServletWebRequest(request));
|
||||
return (types.isEmpty() ? Collections.singletonList(MediaType.ALL) : types);
|
||||
return this.contentNegotiationManager.resolveMediaTypes(new ServletWebRequest(request));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -253,11 +253,7 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport
|
||||
Assert.state(this.contentNegotiationManager != null, "No ContentNegotiationManager set");
|
||||
try {
|
||||
ServletWebRequest webRequest = new ServletWebRequest(request);
|
||||
|
||||
List<MediaType> acceptableMediaTypes = this.contentNegotiationManager.resolveMediaTypes(webRequest);
|
||||
acceptableMediaTypes = (!acceptableMediaTypes.isEmpty() ? acceptableMediaTypes :
|
||||
Collections.singletonList(MediaType.ALL));
|
||||
|
||||
List<MediaType> producibleMediaTypes = getProducibleMediaTypes(request);
|
||||
Set<MediaType> compatibleMediaTypes = new LinkedHashSet<>();
|
||||
for (MediaType acceptable : acceptableMediaTypes) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -25,6 +25,7 @@ import org.junit.Test;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.test.MockHttpServletRequest;
|
||||
import org.springframework.web.accept.ContentNegotiationManager;
|
||||
import org.springframework.web.accept.ContentNegotiationStrategy;
|
||||
import org.springframework.web.accept.FixedContentNegotiationStrategy;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.context.request.ServletWebRequest;
|
||||
@@ -65,7 +66,7 @@ public class ContentNegotiationConfigurerTests {
|
||||
this.servletRequest.addParameter("format", "gif");
|
||||
|
||||
assertEquals("Should not resolve request parameters by default",
|
||||
Collections.emptyList(), manager.resolveMediaTypes(this.webRequest));
|
||||
ContentNegotiationStrategy.MEDIA_TYPE_ALL_LIST, manager.resolveMediaTypes(this.webRequest));
|
||||
|
||||
this.servletRequest.setRequestURI("/flower");
|
||||
this.servletRequest.addHeader("Accept", MediaType.IMAGE_GIF_VALUE);
|
||||
@@ -104,7 +105,7 @@ public class ContentNegotiationConfigurerTests {
|
||||
this.servletRequest.setRequestURI("/flower");
|
||||
this.servletRequest.addHeader("Accept", MediaType.IMAGE_GIF_VALUE);
|
||||
|
||||
assertEquals(Collections.emptyList(), manager.resolveMediaTypes(this.webRequest));
|
||||
assertEquals(ContentNegotiationStrategy.MEDIA_TYPE_ALL_LIST, manager.resolveMediaTypes(this.webRequest));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user