Polish ContentNegotiationStrategy support
Issue: SPR-8410, SPR-8417, SPR-8418,SPR-8416, SPR-8419,SPR-7722
This commit is contained in:
@@ -31,14 +31,14 @@ import org.springframework.web.context.request.NativeWebRequest;
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.2
|
||||
*/
|
||||
public abstract class AbstractMappingContentNegotiationStrategy extends MappingMediaTypeExtensionsResolver
|
||||
implements ContentNegotiationStrategy, MediaTypeExtensionsResolver {
|
||||
public abstract class AbstractMappingContentNegotiationStrategy extends MappingMediaTypeFileExtensionResolver
|
||||
implements ContentNegotiationStrategy, MediaTypeFileExtensionResolver {
|
||||
|
||||
/**
|
||||
* Create an instance with the given extension-to-MediaType lookup.
|
||||
* @throws IllegalArgumentException if a media type string cannot be parsed
|
||||
*/
|
||||
public AbstractMappingContentNegotiationStrategy(Map<String, String> mediaTypes) {
|
||||
public AbstractMappingContentNegotiationStrategy(Map<String, MediaType> mediaTypes) {
|
||||
super(mediaTypes);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,28 +33,30 @@ import org.springframework.web.context.request.NativeWebRequest;
|
||||
* in a request by delegating to a list of {@link ContentNegotiationStrategy} instances.
|
||||
*
|
||||
* <p>It may also be used to determine the extensions associated with a MediaType by
|
||||
* delegating to a list of {@link MediaTypeExtensionsResolver} instances.
|
||||
* delegating to a list of {@link MediaTypeFileExtensionResolver} instances.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.2
|
||||
*/
|
||||
public class ContentNegotiationManager implements ContentNegotiationStrategy, MediaTypeExtensionsResolver {
|
||||
public class ContentNegotiationManager implements ContentNegotiationStrategy, MediaTypeFileExtensionResolver {
|
||||
|
||||
private final List<ContentNegotiationStrategy> contentNegotiationStrategies = new ArrayList<ContentNegotiationStrategy>();
|
||||
private final List<ContentNegotiationStrategy> contentNegotiationStrategies =
|
||||
new ArrayList<ContentNegotiationStrategy>();
|
||||
|
||||
private final Set<MediaTypeExtensionsResolver> extensionResolvers = new LinkedHashSet<MediaTypeExtensionsResolver>();
|
||||
private final Set<MediaTypeFileExtensionResolver> fileExtensionResolvers =
|
||||
new LinkedHashSet<MediaTypeFileExtensionResolver>();
|
||||
|
||||
/**
|
||||
* Create an instance with the given ContentNegotiationStrategy instances.
|
||||
* <p>Each instance is checked to see if it is also an implementation of
|
||||
* MediaTypeExtensionsResolver, and if so it is registered as such.
|
||||
* MediaTypeFileExtensionResolver, and if so it is registered as such.
|
||||
*/
|
||||
public ContentNegotiationManager(ContentNegotiationStrategy... strategies) {
|
||||
Assert.notEmpty(strategies, "At least one ContentNegotiationStrategy is expected");
|
||||
this.contentNegotiationStrategies.addAll(Arrays.asList(strategies));
|
||||
for (ContentNegotiationStrategy strategy : this.contentNegotiationStrategies) {
|
||||
if (strategy instanceof MediaTypeExtensionsResolver) {
|
||||
this.extensionResolvers.add((MediaTypeExtensionsResolver) strategy);
|
||||
if (strategy instanceof MediaTypeFileExtensionResolver) {
|
||||
this.fileExtensionResolvers.add((MediaTypeFileExtensionResolver) strategy);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -67,10 +69,10 @@ public class ContentNegotiationManager implements ContentNegotiationStrategy, Me
|
||||
}
|
||||
|
||||
/**
|
||||
* Add MediaTypeExtensionsResolver instances.
|
||||
* Add MediaTypeFileExtensionResolver instances.
|
||||
*/
|
||||
public void addExtensionsResolver(MediaTypeExtensionsResolver... resolvers) {
|
||||
this.extensionResolvers.addAll(Arrays.asList(resolvers));
|
||||
public void addFileExtensionResolvers(MediaTypeFileExtensionResolver... resolvers) {
|
||||
this.fileExtensionResolvers.addAll(Arrays.asList(resolvers));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -91,13 +93,13 @@ public class ContentNegotiationManager implements ContentNegotiationStrategy, Me
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegate to all configured MediaTypeExtensionsResolver instances and aggregate
|
||||
* the list of all extensions found.
|
||||
* Delegate to all configured MediaTypeFileExtensionResolver instances and aggregate
|
||||
* the list of all file extensions found.
|
||||
*/
|
||||
public List<String> resolveExtensions(MediaType mediaType) {
|
||||
public List<String> resolveFileExtensions(MediaType mediaType) {
|
||||
Set<String> extensions = new LinkedHashSet<String>();
|
||||
for (MediaTypeExtensionsResolver resolver : this.extensionResolvers) {
|
||||
extensions.addAll(resolver.resolveExtensions(mediaType));
|
||||
for (MediaTypeFileExtensionResolver resolver : this.fileExtensionResolvers) {
|
||||
extensions.addAll(resolver.resolveFileExtensions(mediaType));
|
||||
}
|
||||
return new ArrayList<String>(extensions);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package org.springframework.web.accept;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
@@ -24,28 +24,32 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
* An implementation of {@link MediaTypeExtensionsResolver} that maintains a lookup
|
||||
* An implementation of {@link MediaTypeFileExtensionResolver} that maintains a lookup
|
||||
* from extension to MediaType.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.2
|
||||
*/
|
||||
public class MappingMediaTypeExtensionsResolver implements MediaTypeExtensionsResolver {
|
||||
public class MappingMediaTypeFileExtensionResolver implements MediaTypeFileExtensionResolver {
|
||||
|
||||
private ConcurrentMap<String, MediaType> mediaTypes = new ConcurrentHashMap<String, MediaType>();
|
||||
private final ConcurrentMap<String, MediaType> mediaTypes = new ConcurrentHashMap<String, MediaType>();
|
||||
|
||||
private final MultiValueMap<MediaType, String> fileExtensions = new LinkedMultiValueMap<MediaType, String>();
|
||||
|
||||
/**
|
||||
* Create an instance with the given mappings between extensions and media types.
|
||||
* @throws IllegalArgumentException if a media type string cannot be parsed
|
||||
*/
|
||||
public MappingMediaTypeExtensionsResolver(Map<String, String> mediaTypes) {
|
||||
public MappingMediaTypeFileExtensionResolver(Map<String, MediaType> mediaTypes) {
|
||||
if (mediaTypes != null) {
|
||||
for (Map.Entry<String, String> entry : mediaTypes.entrySet()) {
|
||||
String extension = entry.getKey().toLowerCase(Locale.ENGLISH);
|
||||
MediaType mediaType = MediaType.parseMediaType(entry.getValue());
|
||||
this.mediaTypes.put(extension, mediaType);
|
||||
for (Entry<String, MediaType> entries : mediaTypes.entrySet()) {
|
||||
String extension = entries.getKey().toLowerCase(Locale.ENGLISH);
|
||||
MediaType mediaType = entries.getValue();
|
||||
addMapping(extension, mediaType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,14 +58,9 @@ public class MappingMediaTypeExtensionsResolver implements MediaTypeExtensionsRe
|
||||
* Find the extensions applicable to the given MediaType.
|
||||
* @return 0 or more extensions, never {@code null}
|
||||
*/
|
||||
public List<String> resolveExtensions(MediaType mediaType) {
|
||||
List<String> result = new ArrayList<String>();
|
||||
for (Entry<String, MediaType> entry : this.mediaTypes.entrySet()) {
|
||||
if (mediaType.includes(entry.getValue())) {
|
||||
result.add(entry.getKey());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
public List<String> resolveFileExtensions(MediaType mediaType) {
|
||||
List<String> fileExtensions = this.fileExtensions.get(mediaType);
|
||||
return (fileExtensions != null) ? fileExtensions : Collections.<String>emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -76,7 +75,10 @@ public class MappingMediaTypeExtensionsResolver implements MediaTypeExtensionsRe
|
||||
* Map a MediaType to an extension or ignore if the extensions is already mapped.
|
||||
*/
|
||||
protected void addMapping(String extension, MediaType mediaType) {
|
||||
this.mediaTypes.putIfAbsent(extension, mediaType);
|
||||
MediaType previous = this.mediaTypes.putIfAbsent(extension, mediaType);
|
||||
if (previous == null) {
|
||||
this.fileExtensions.add(mediaType, extension);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -27,7 +27,7 @@ import org.springframework.http.MediaType;
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.2
|
||||
*/
|
||||
public interface MediaTypeExtensionsResolver {
|
||||
public interface MediaTypeFileExtensionResolver {
|
||||
|
||||
/**
|
||||
* Resolve the given media type to a list of path extensions.
|
||||
@@ -35,6 +35,6 @@ public interface MediaTypeExtensionsResolver {
|
||||
* @param mediaType the media type to resolve
|
||||
* @return a list of extensions or an empty list, never {@code null}
|
||||
*/
|
||||
List<String> resolveExtensions(MediaType mediaType);
|
||||
List<String> resolveFileExtensions(MediaType mediaType);
|
||||
|
||||
}
|
||||
@@ -42,7 +42,7 @@ public class ParameterContentNegotiationStrategy extends AbstractMappingContentN
|
||||
* Create an instance with the given extension-to-MediaType lookup.
|
||||
* @throws IllegalArgumentException if a media type string cannot be parsed
|
||||
*/
|
||||
public ParameterContentNegotiationStrategy(Map<String, String> mediaTypes) {
|
||||
public ParameterContentNegotiationStrategy(Map<String, MediaType> mediaTypes) {
|
||||
super(mediaTypes);
|
||||
Assert.notEmpty(mediaTypes, "Cannot look up media types without any mappings");
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ public class PathExtensionContentNegotiationStrategy extends AbstractMappingCont
|
||||
* Create an instance with the given extension-to-MediaType lookup.
|
||||
* @throws IllegalArgumentException if a media type string cannot be parsed
|
||||
*/
|
||||
public PathExtensionContentNegotiationStrategy(Map<String, String> mediaTypes) {
|
||||
public PathExtensionContentNegotiationStrategy(Map<String, MediaType> mediaTypes) {
|
||||
super(mediaTypes);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user