Browse Source

Refactor RequestedContentTypeResolverBuilder

The revised builder emphasizes creating a list of resolvers either
built-in or custom with each top-level builder method resulting in
adding a resolver.

By default only the Header resolver is configured.

The path extension resolver is removed altogether to discourage its use
but is trivial to create manually with the helpf of
UriUtils#extractFileExtension + MediaTypeFactory.

Issue: SPR-15639
pull/1457/head
Rossen Stoyanchev 8 years ago
parent
commit
01a92517bd
  1. 82
      spring-webflux/src/main/java/org/springframework/web/reactive/accept/AbstractMappingContentTypeResolver.java
  2. 55
      spring-webflux/src/main/java/org/springframework/web/reactive/accept/CompositeContentTypeResolver.java
  3. 5
      spring-webflux/src/main/java/org/springframework/web/reactive/accept/FixedContentTypeResolver.java
  4. 2
      spring-webflux/src/main/java/org/springframework/web/reactive/accept/HeaderContentTypeResolver.java
  5. 46
      spring-webflux/src/main/java/org/springframework/web/reactive/accept/ParameterContentTypeResolver.java
  6. 45
      spring-webflux/src/main/java/org/springframework/web/reactive/accept/PathExtensionContentTypeResolver.java
  7. 8
      spring-webflux/src/main/java/org/springframework/web/reactive/accept/RequestedContentTypeResolver.java
  8. 234
      spring-webflux/src/main/java/org/springframework/web/reactive/accept/RequestedContentTypeResolverBuilder.java
  9. 19
      spring-webflux/src/main/java/org/springframework/web/reactive/config/WebFluxConfigurationSupport.java
  10. 8
      spring-webflux/src/main/java/org/springframework/web/reactive/config/WebFluxConfigurer.java
  11. 7
      spring-webflux/src/main/java/org/springframework/web/reactive/result/condition/ProducesRequestCondition.java
  12. 132
      spring-webflux/src/test/java/org/springframework/web/reactive/accept/CompositeContentTypeResolverBuilderTests.java
  13. 103
      spring-webflux/src/test/java/org/springframework/web/reactive/accept/MappingContentTypeResolverTests.java
  14. 92
      spring-webflux/src/test/java/org/springframework/web/reactive/accept/ParameterContentTypeResolverTests.java
  15. 83
      spring-webflux/src/test/java/org/springframework/web/reactive/accept/PathExtensionContentTypeResolverTests.java
  16. 100
      spring-webflux/src/test/java/org/springframework/web/reactive/accept/RequestedContentTypeResolverBuilderTests.java
  17. 10
      spring-webflux/src/test/java/org/springframework/web/reactive/config/WebFluxConfigurationSupportTests.java
  18. 12
      spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/MessageWriterResultHandlerTests.java
  19. 2
      spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandlerTests.java
  20. 2
      spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ResponseEntityResultHandlerTests.java

82
spring-webflux/src/main/java/org/springframework/web/reactive/accept/AbstractMappingContentTypeResolver.java

@ -1,82 +0,0 @@ @@ -1,82 +0,0 @@
/*
* Copyright 2002-2017 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.reactive.accept;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.http.MediaType;
import org.springframework.http.MediaTypeFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
/**
* Base class for resolvers that extract a key from the request and look up a
* mapping to a MediaType. The use case is URI-based content negotiation for
* example based on query parameter or file extension in the request path.
*
* @author Rossen Stoyanchev
* @since 5.0
*/
public abstract class AbstractMappingContentTypeResolver implements RequestedContentTypeResolver {
/** Primary lookup for media types by key (e.g. "json" -> "application/json") */
private final Map<String, MediaType> mediaTypeLookup = new ConcurrentHashMap<>(64);
public AbstractMappingContentTypeResolver(Map<String, MediaType> mediaTypes) {
mediaTypes.forEach((key, mediaType) ->
this.mediaTypeLookup.put(key.toLowerCase(Locale.ENGLISH), mediaType));
}
@Override
public List<MediaType> resolveMediaTypes(ServerWebExchange exchange) {
String key = getKey(exchange);
if (StringUtils.hasText(key)) {
MediaType mediaType = getMediaType(key);
if (mediaType != null) {
this.mediaTypeLookup.putIfAbsent(key, mediaType);
return Collections.singletonList(mediaType);
}
}
return Collections.emptyList();
}
/**
* Get the key to look up a MediaType with.
*/
@Nullable
protected abstract String getKey(ServerWebExchange exchange);
/**
* Get the MediaType for the given key.
*/
@Nullable
protected MediaType getMediaType(String key) {
key = key.toLowerCase(Locale.ENGLISH);
MediaType mediaType = this.mediaTypeLookup.get(key);
if (mediaType == null) {
mediaType = MediaTypeFactory.getMediaType("filename." + key).orElse(null);
}
return mediaType;
}
}

55
spring-webflux/src/main/java/org/springframework/web/reactive/accept/CompositeContentTypeResolver.java

@ -1,55 +0,0 @@ @@ -1,55 +0,0 @@
/*
* Copyright 2002-2017 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.reactive.accept;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.springframework.http.MediaType;
import org.springframework.util.Assert;
import org.springframework.web.server.ServerWebExchange;
/**
* Contains and delegates to other {@link RequestedContentTypeResolver}.
*
* @author Rossen Stoyanchev
* @since 5.0
*/
public class CompositeContentTypeResolver implements RequestedContentTypeResolver {
private final List<RequestedContentTypeResolver> resolvers = new ArrayList<>();
public CompositeContentTypeResolver(List<RequestedContentTypeResolver> resolvers) {
Assert.notEmpty(resolvers, "At least one resolver is expected.");
this.resolvers.addAll(resolvers);
}
@Override
public List<MediaType> resolveMediaTypes(ServerWebExchange exchange) {
for (RequestedContentTypeResolver resolver : this.resolvers) {
List<MediaType> mediaTypes = resolver.resolveMediaTypes(exchange);
if (mediaTypes.isEmpty() || (mediaTypes.size() == 1 && mediaTypes.contains(MediaType.ALL))) {
continue;
}
return mediaTypes;
}
return Collections.emptyList();
}
}

5
spring-webflux/src/main/java/org/springframework/web/reactive/accept/FixedContentTypeResolver.java

@ -26,7 +26,9 @@ import org.springframework.http.MediaType; @@ -26,7 +26,9 @@ import org.springframework.http.MediaType;
import org.springframework.web.server.ServerWebExchange;
/**
* {@code RequestedContentTypeResolver} with a fixed list of media types.
* Resolver that always resolves to a fixed list of media types. This can be
* used as the "last in line" strategy providing a fallback for when the client
* has not requested any media types.
*
* @author Rossen Stoyanchev
* @since 5.0
@ -65,7 +67,6 @@ public class FixedContentTypeResolver implements RequestedContentTypeResolver { @@ -65,7 +67,6 @@ public class FixedContentTypeResolver implements RequestedContentTypeResolver {
}
@Override
public List<MediaType> resolveMediaTypes(ServerWebExchange exchange) {
if (logger.isDebugEnabled()) {

2
spring-webflux/src/main/java/org/springframework/web/reactive/accept/HeaderContentTypeResolver.java

@ -23,7 +23,7 @@ import org.springframework.web.server.NotAcceptableStatusException; @@ -23,7 +23,7 @@ import org.springframework.web.server.NotAcceptableStatusException;
import org.springframework.web.server.ServerWebExchange;
/**
* A {@link RequestedContentTypeResolver} that checks the 'Accept' request header.
* Resolver that looks at the 'Accept' header of the request.
*
* @author Rossen Stoyanchev
* @since 5.0

46
spring-webflux/src/main/java/org/springframework/web/reactive/accept/ParameterContentTypeResolver.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2017 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.
@ -13,34 +13,50 @@ @@ -13,34 +13,50 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.reactive.accept;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.http.MediaType;
import org.springframework.http.MediaTypeFactory;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.server.NotAcceptableStatusException;
import org.springframework.web.server.ServerWebExchange;
/**
* Query parameter based {@link AbstractMappingContentTypeResolver}.
* Resolver that checks a query parameter and uses it to lookup a matching
* MediaType. Lookup keys can be registered or as a fallback
* {@link MediaTypeFactory} can be used to perform a lookup.
*
* @author Rossen Stoyanchev
* @since 5.0
*/
public class ParameterContentTypeResolver extends AbstractMappingContentTypeResolver {
public class ParameterContentTypeResolver implements RequestedContentTypeResolver {
/** Primary lookup for media types by key (e.g. "json" -> "application/json") */
private final Map<String, MediaType> mediaTypes = new ConcurrentHashMap<>(64);
private String parameterName = "format";
public ParameterContentTypeResolver(Map<String, MediaType> mediaTypes) {
super(mediaTypes);
mediaTypes.forEach((key, value) -> this.mediaTypes.put(formatKey(key), value));
}
private static String formatKey(String key) {
return key.toLowerCase(Locale.ENGLISH);
}
/**
* Set the name of the parameter to use to determine requested media types.
* <p>By default this is set to {@code "format"}.
* <p>By default this is set to {@literal "format"}.
*/
public void setParameterName(String parameterName) {
Assert.notNull(parameterName, "'parameterName' is required");
@ -53,8 +69,22 @@ public class ParameterContentTypeResolver extends AbstractMappingContentTypeReso @@ -53,8 +69,22 @@ public class ParameterContentTypeResolver extends AbstractMappingContentTypeReso
@Override
protected String getKey(ServerWebExchange exchange) {
return exchange.getRequest().getQueryParams().getFirst(getParameterName());
public List<MediaType> resolveMediaTypes(ServerWebExchange exchange) throws NotAcceptableStatusException {
String key = exchange.getRequest().getQueryParams().getFirst(getParameterName());
if (!StringUtils.hasText(key)) {
return Collections.emptyList();
}
key = formatKey(key);
MediaType match = this.mediaTypes.get(key);
if (match == null) {
match = MediaTypeFactory.getMediaType("filename." + key)
.orElseThrow(() -> {
List<MediaType> supported = new ArrayList<>(this.mediaTypes.values());
return new NotAcceptableStatusException(supported);
});
}
this.mediaTypes.putIfAbsent(key, match);
return Collections.singletonList(match);
}
}

45
spring-webflux/src/main/java/org/springframework/web/reactive/accept/PathExtensionContentTypeResolver.java

@ -1,45 +0,0 @@ @@ -1,45 +0,0 @@
/*
* Copyright 2002-2017 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.reactive.accept;
import java.util.Map;
import org.springframework.http.MediaType;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.UriUtils;
/**
* Path file extension sub-class of {@link AbstractMappingContentTypeResolver}.
*
* @author Rossen Stoyanchev
* @since 5.0
*/
public class PathExtensionContentTypeResolver extends AbstractMappingContentTypeResolver {
public PathExtensionContentTypeResolver(Map<String, MediaType> mediaTypes) {
super(mediaTypes);
}
@Override
protected String getKey(ServerWebExchange exchange) {
String path = exchange.getRequest().getURI().getRawPath();
return UriUtils.extractFileExtension(path);
}
}

8
spring-webflux/src/main/java/org/springframework/web/reactive/accept/RequestedContentTypeResolver.java

@ -23,8 +23,10 @@ import org.springframework.web.server.NotAcceptableStatusException; @@ -23,8 +23,10 @@ import org.springframework.web.server.NotAcceptableStatusException;
import org.springframework.web.server.ServerWebExchange;
/**
* Strategy for resolving the requested media types for a
* {@code ServerWebExchange}.
* Strategy to resolve the requested media types for a {@code ServerWebExchange}.
*
* <p>See {@link RequestedContentTypeResolverBuilder} to create a sequence of
* strategies.
*
* @author Rossen Stoyanchev
* @since 5.0
@ -36,7 +38,7 @@ public interface RequestedContentTypeResolver { @@ -36,7 +38,7 @@ public interface RequestedContentTypeResolver {
* list is ordered by specificity first and by quality parameter second.
* @param exchange the current exchange
* @return the requested media types or an empty list
* @throws NotAcceptableStatusException if the requested media types is invalid
* @throws NotAcceptableStatusException if the requested media type is invalid
*/
List<MediaType> resolveMediaTypes(ServerWebExchange exchange);

234
spring-webflux/src/main/java/org/springframework/web/reactive/accept/RequestedContentTypeResolverBuilder.java

@ -17,209 +17,141 @@ package org.springframework.web.reactive.accept; @@ -17,209 +17,141 @@ package org.springframework.web.reactive.accept;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import org.springframework.http.MediaType;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
/**
* Factory to create a {@link CompositeContentTypeResolver} and configure it with
* one or more {@link RequestedContentTypeResolver} instances with build style
* methods. The following table shows methods, resulting strategy instances, and
* if in use by default:
* Builder for a composite {@link RequestedContentTypeResolver} that delegates
* to one or more other resolvers each implementing a different strategy to
* determine the requested content type(s), e.g. from the Accept header,
* through a query parameter, or other custom strategy.
*
* <table>
* <tr>
* <th>Property Setter</th>
* <th>Underlying Strategy</th>
* <th>Default Setting</th>
* </tr>
* <tr>
* <td>{@link #favorPathExtension}</td>
* <td>{@link PathExtensionContentTypeResolver Path Extension resolver}</td>
* <td>On</td>
* </tr>
* <tr>
* <td>{@link #favorParameter}</td>
* <td>{@link ParameterContentTypeResolver Parameter resolver}</td>
* <td>Off</td>
* </tr>
* <tr>
* <td>{@link #ignoreAcceptHeader}</td>
* <td>{@link HeaderContentTypeResolver Header resolver}</td>
* <td>Off</td>
* </tr>
* <tr>
* <td>{@link #defaultContentType}</td>
* <td>{@link FixedContentTypeResolver Fixed content resolver}</td>
* <td>Not set</td>
* </tr>
* <tr>
* <td>{@link #defaultContentTypeResolver}</td>
* <td>{@link RequestedContentTypeResolver}</td>
* <td>Not set</td>
* </tr>
* </table>
* <p>Use methods of this builder to add resolvers in the desired order.
* The result of the first resolver to return a non-empty list of media types
* is used.
*
* <p>The order in which resolvers are configured is fixed. Config methods may
* only turn individual resolvers on or off. If you need a custom order for any
* reason simply instantiate {@code {@link CompositeContentTypeResolver}}
* directly.
*
* <p>For the path extension and parameter resolvers you may explicitly add
* {@link #mediaTypes(Map)}. This will be used to resolve path extensions or a
* parameter value such as "json" to a media type such as "application/json".
*
* <p>The path extension strategy will also use
* {@link org.springframework.http.MediaTypeFactory} to resolve a path extension
* to a MediaType.
* <p>If no resolvers are configured, by default the builder will configure
* {@link HeaderContentTypeResolver} only.
*
* @author Rossen Stoyanchev
* @since 5.0
*/
public class RequestedContentTypeResolverBuilder {
private boolean favorPathExtension = true;
private boolean favorParameter = false;
private boolean ignoreAcceptHeader = false;
private Map<String, MediaType> mediaTypes = new HashMap<>();
private String parameterName = "format";
private RequestedContentTypeResolver contentTypeResolver;
private final List<Supplier<RequestedContentTypeResolver>> candidates = new ArrayList<>();
/**
* Whether the path extension in the URL path should be used to determine
* the requested media type.
* <p>By default this is set to {@code true} in which case a request
* for {@code /hotels.pdf} will be interpreted as a request for
* {@code "application/pdf"} regardless of the 'Accept' header.
* Add resolver extracting the requested content type from a query parameter.
* By default the expected query parameter name is {@code "format"}.
*/
public RequestedContentTypeResolverBuilder favorPathExtension(boolean favorPathExtension) {
this.favorPathExtension = favorPathExtension;
return this;
public ParameterResolverConfigurer parameterResolver() {
ParameterResolverConfigurer parameterBuilder = new ParameterResolverConfigurer();
this.candidates.add(parameterBuilder::createResolver);
return parameterBuilder;
}
/**
* Add a mapping from a key, extracted from a path extension or a query
* parameter, to a MediaType. This is required in order for the parameter
* strategy to work. Any extensions explicitly registered here are also
* whitelisted for the purpose of Reflected File Download attack detection
* (see Spring Framework reference documentation for more details on RFD
* attack protection).
* <p>The path extension strategy will also use the
* {@link org.springframework.http.MediaTypeFactory} to resolve path
* extensions.
* @param mediaTypes media type mappings
* Add resolver extracting the requested content type from the
* {@literal "Accept"} header.
*/
public RequestedContentTypeResolverBuilder mediaTypes(Map<String, MediaType> mediaTypes) {
if (!CollectionUtils.isEmpty(mediaTypes)) {
for (Map.Entry<String, MediaType> entry : mediaTypes.entrySet()) {
String extension = entry.getKey().toLowerCase(Locale.ENGLISH);
this.mediaTypes.put(extension, entry.getValue());
}
}
return this;
public void headerResolver() {
this.candidates.add(HeaderContentTypeResolver::new);
}
/**
* Alternative to {@link #mediaTypes} to add a single mapping.
* Add resolver that always returns a fixed set of media types.
* @param mediaTypes the media types to use
*/
public RequestedContentTypeResolverBuilder mediaType(String key, MediaType mediaType) {
this.mediaTypes.put(key, mediaType);
return this;
public void fixedResolver(MediaType... mediaTypes) {
this.candidates.add(() -> new FixedContentTypeResolver(Arrays.asList(mediaTypes)));
}
/**
* Whether a request parameter ("format" by default) should be used to
* determine the requested media type. For this option to work you must
* register {@link #mediaTypes media type mappings}.
* <p>By default this is set to {@code false}.
* @see #parameterName
* Add a custom resolver.
* @param resolver the resolver to add
*/
public RequestedContentTypeResolverBuilder favorParameter(boolean favorParameter) {
this.favorParameter = favorParameter;
return this;
public void resolver(RequestedContentTypeResolver resolver) {
this.candidates.add(() -> resolver);
}
/**
* Set the query parameter name to use when {@link #favorParameter} is on.
* <p>The default parameter name is {@code "format"}.
* Build a {@link RequestedContentTypeResolver} that delegates to the list
* of resolvers configured through this builder.
*/
public RequestedContentTypeResolverBuilder parameterName(String parameterName) {
Assert.notNull(parameterName, "parameterName is required");
this.parameterName = parameterName;
return this;
public RequestedContentTypeResolver build() {
List<RequestedContentTypeResolver> resolvers =
this.candidates.isEmpty() ?
Collections.singletonList(new HeaderContentTypeResolver()) :
this.candidates.stream().map(Supplier::get).collect(Collectors.toList());
return exchange -> {
for (RequestedContentTypeResolver resolver : resolvers) {
List<MediaType> type = resolver.resolveMediaTypes(exchange);
if (type.isEmpty() || (type.size() == 1 && type.contains(MediaType.ALL))) {
continue;
}
return type;
}
return Collections.emptyList();
};
}
/**
* Whether to disable checking the 'Accept' request header.
* <p>By default this value is set to {@code false}.
*/
public RequestedContentTypeResolverBuilder ignoreAcceptHeader(boolean ignoreAcceptHeader) {
this.ignoreAcceptHeader = ignoreAcceptHeader;
return this;
}
/**
* Set the default content type(s) to use when no content type is requested
* in order of priority.
*
* <p>If destinations are present that do not support any of the given media
* types, consider appending {@link MediaType#ALL} at the end.
*
* <p>By default this is not set.
*
* @see #defaultContentTypeResolver
* Helps to create a {@link ParameterContentTypeResolver}.
*/
public RequestedContentTypeResolverBuilder defaultContentType(MediaType... contentTypes) {
this.contentTypeResolver = new FixedContentTypeResolver(Arrays.asList(contentTypes));
return this;
}
public static class ParameterResolverConfigurer {
/**
* Set a custom {@link RequestedContentTypeResolver} to use to determine
* the content type to use when no content type is requested.
* <p>By default this is not set.
* @see #defaultContentType
*/
public RequestedContentTypeResolverBuilder defaultContentTypeResolver(RequestedContentTypeResolver resolver) {
this.contentTypeResolver = resolver;
return this;
}
private final Map<String, MediaType> mediaTypes = new HashMap<>();
private String parameterName;
public CompositeContentTypeResolver build() {
List<RequestedContentTypeResolver> resolvers = new ArrayList<>();
if (this.favorPathExtension) {
resolvers.add(new PathExtensionContentTypeResolver(this.mediaTypes));
/**
* Configure a mapping between a lookup key (extracted from a query
* parameter value) and a corresponding {@code MediaType}.
* @param key the lookup key
* @param mediaType the MediaType for that key
*/
public ParameterResolverConfigurer mediaType(String key, MediaType mediaType) {
this.mediaTypes.put(key, mediaType);
return this;
}
if (this.favorParameter) {
ParameterContentTypeResolver resolver = new ParameterContentTypeResolver(this.mediaTypes);
resolver.setParameterName(this.parameterName);
resolvers.add(resolver);
/**
* Map-based variant of {@link #mediaType(String, MediaType)}.
* @param mediaTypes the mappings to copy
*/
public ParameterResolverConfigurer mediaType(Map<String, MediaType> mediaTypes) {
this.mediaTypes.putAll(mediaTypes);
return this;
}
if (!this.ignoreAcceptHeader) {
resolvers.add(new HeaderContentTypeResolver());
/**
* Set the name of the parameter to use to determine requested media types.
* <p>By default this is set to {@literal "format"}.
*/
public ParameterResolverConfigurer parameterName(String parameterName) {
this.parameterName = parameterName;
return this;
}
if (this.contentTypeResolver != null) {
resolvers.add(this.contentTypeResolver);
RequestedContentTypeResolver createResolver() {
ParameterContentTypeResolver resolver = new ParameterContentTypeResolver(this.mediaTypes);
if (this.parameterName != null) {
resolver.setParameterName(this.parameterName);
}
return resolver;
}
return new CompositeContentTypeResolver(resolvers);
}
}

19
spring-webflux/src/main/java/org/springframework/web/reactive/config/WebFluxConfigurationSupport.java

@ -16,7 +16,6 @@ @@ -16,7 +16,6 @@
package org.springframework.web.reactive.config;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -34,7 +33,6 @@ import org.springframework.format.Formatter; @@ -34,7 +33,6 @@ import org.springframework.format.Formatter;
import org.springframework.format.FormatterRegistry;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.format.support.FormattingConversionService;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
@ -47,7 +45,7 @@ import org.springframework.web.bind.support.ConfigurableWebBindingInitializer; @@ -47,7 +45,7 @@ import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.reactive.DispatcherHandler;
import org.springframework.web.reactive.HandlerMapping;
import org.springframework.web.reactive.accept.CompositeContentTypeResolver;
import org.springframework.web.reactive.accept.RequestedContentTypeResolver;
import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder;
import org.springframework.web.reactive.function.server.support.HandlerFunctionAdapter;
import org.springframework.web.reactive.function.server.support.RouterFunctionMapping;
@ -147,25 +145,12 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware { @@ -147,25 +145,12 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware {
}
@Bean
public CompositeContentTypeResolver webFluxContentTypeResolver() {
public RequestedContentTypeResolver webFluxContentTypeResolver() {
RequestedContentTypeResolverBuilder builder = new RequestedContentTypeResolverBuilder();
builder.mediaTypes(getDefaultMediaTypeMappings());
configureContentTypeResolver(builder);
return builder.build();
}
/**
* Override to configure media type mappings.
* @see RequestedContentTypeResolverBuilder#mediaTypes(Map)
*/
protected Map<String, MediaType> getDefaultMediaTypeMappings() {
Map<String, MediaType> map = new HashMap<>();
if (jackson2Present) {
map.put("json", MediaType.APPLICATION_JSON);
}
return map;
}
/**
* Override to configure how the requested content type is resolved.
*/

8
spring-webflux/src/main/java/org/springframework/web/reactive/config/WebFluxConfigurer.java

@ -23,8 +23,6 @@ import org.springframework.http.codec.ServerCodecConfigurer; @@ -23,8 +23,6 @@ import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.lang.Nullable;
import org.springframework.validation.MessageCodesResolver;
import org.springframework.validation.Validator;
import org.springframework.web.reactive.accept.CompositeContentTypeResolver;
import org.springframework.web.reactive.accept.RequestedContentTypeResolver;
import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder;
import org.springframework.web.reactive.result.method.annotation.ArgumentResolverConfigurer;
@ -45,11 +43,7 @@ public interface WebFluxConfigurer { @@ -45,11 +43,7 @@ public interface WebFluxConfigurer {
/**
* Configure how the content type requested for the response is resolved.
* <p>The given builder will create a composite of multiple
* {@link RequestedContentTypeResolver}s, each defining a way to resolve
* the requested content type (accept HTTP header, path extension,
* parameter, etc).
* @param builder factory that creates a {@link CompositeContentTypeResolver}
* @param builder for configuring the resolvers to use
*/
default void configureContentTypeResolver(RequestedContentTypeResolverBuilder builder) {
}

7
spring-webflux/src/main/java/org/springframework/web/reactive/result/condition/ProducesRequestCondition.java

@ -28,9 +28,9 @@ import org.springframework.http.MediaType; @@ -28,9 +28,9 @@ import org.springframework.http.MediaType;
import org.springframework.web.accept.ContentNegotiationManager;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.cors.reactive.CorsUtils;
import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder;
import org.springframework.web.reactive.accept.RequestedContentTypeResolver;
import org.springframework.web.reactive.accept.HeaderContentTypeResolver;
import org.springframework.web.reactive.accept.RequestedContentTypeResolver;
import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder;
import org.springframework.web.server.NotAcceptableStatusException;
import org.springframework.web.server.ServerWebExchange;
@ -99,8 +99,7 @@ public final class ProducesRequestCondition extends AbstractRequestCondition<Pro @@ -99,8 +99,7 @@ public final class ProducesRequestCondition extends AbstractRequestCondition<Pro
this.expressions = new ArrayList<>(expressions);
Collections.sort(this.expressions);
this.contentTypeResolver = (resolver != null ?
resolver : new RequestedContentTypeResolverBuilder().build());
this.contentTypeResolver = (resolver != null ? resolver : new RequestedContentTypeResolverBuilder().build());
}

132
spring-webflux/src/test/java/org/springframework/web/reactive/accept/CompositeContentTypeResolverBuilderTests.java

@ -1,132 +0,0 @@ @@ -1,132 +0,0 @@
/*
* Copyright 2002-2017 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.reactive.accept;
import java.util.Collections;
import java.util.List;
import org.junit.Test;
import org.springframework.http.MediaType;
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
import org.springframework.mock.http.server.reactive.test.MockServerWebExchange;
import org.springframework.web.server.ServerWebExchange;
import static org.junit.Assert.assertEquals;
/**
* Unit tests for {@link RequestedContentTypeResolverBuilder}.
*
* @author Rossen Stoyanchev
*/
public class CompositeContentTypeResolverBuilderTests {
@Test
public void defaultSettings() throws Exception {
RequestedContentTypeResolver resolver = new RequestedContentTypeResolverBuilder().build();
MockServerWebExchange exchange = MockServerHttpRequest.get("/flower.gif").toExchange();
assertEquals("Should be able to resolve file extensions by default",
Collections.singletonList(MediaType.IMAGE_GIF), resolver.resolveMediaTypes(exchange));
exchange = MockServerHttpRequest.get("/flower.foobar").toExchange();
assertEquals("Should ignore unknown extensions by default",
Collections.<MediaType>emptyList(), resolver.resolveMediaTypes(exchange));
exchange = MockServerHttpRequest.get("/flower?format=gif").toExchange();
assertEquals("Should not resolve request parameters by default",
Collections.<MediaType>emptyList(), resolver.resolveMediaTypes(exchange));
exchange = MockServerHttpRequest.get("/flower").accept(MediaType.IMAGE_GIF).toExchange();
assertEquals("Should resolve Accept header by default",
Collections.singletonList(MediaType.IMAGE_GIF), resolver.resolveMediaTypes(exchange));
}
@Test
public void favorPath() throws Exception {
RequestedContentTypeResolver resolver = new RequestedContentTypeResolverBuilder()
.favorPathExtension(true)
.mediaType("foo", new MediaType("application", "foo"))
.mediaType("bar", new MediaType("application", "bar"))
.build();
ServerWebExchange exchange = MockServerHttpRequest.get("/flower.foo").toExchange();
assertEquals(Collections.singletonList(new MediaType("application", "foo")),
resolver.resolveMediaTypes(exchange));
exchange = MockServerHttpRequest.get("/flower.bar").toExchange();
assertEquals(Collections.singletonList(new MediaType("application", "bar")),
resolver.resolveMediaTypes(exchange));
exchange = MockServerHttpRequest.get("/flower.gif").toExchange();
assertEquals(Collections.singletonList(MediaType.IMAGE_GIF), resolver.resolveMediaTypes(exchange));
}
@Test
public void favorParameter() throws Exception {
RequestedContentTypeResolver resolver = new RequestedContentTypeResolverBuilder()
.favorParameter(true)
.mediaType("json", MediaType.APPLICATION_JSON)
.build();
ServerWebExchange exchange = MockServerHttpRequest.get("/flower?format=json").toExchange();
assertEquals(Collections.singletonList(MediaType.APPLICATION_JSON), resolver.resolveMediaTypes(exchange));
}
@Test
public void ignoreAcceptHeader() throws Exception {
RequestedContentTypeResolver resolver = new RequestedContentTypeResolverBuilder()
.ignoreAcceptHeader(true)
.build();
ServerWebExchange exchange = MockServerHttpRequest.get("/flower").accept(MediaType.IMAGE_GIF).toExchange();
assertEquals(Collections.<MediaType>emptyList(), resolver.resolveMediaTypes(exchange));
}
@Test // SPR-10513
public void setDefaultContentType() throws Exception {
RequestedContentTypeResolver resolver = new RequestedContentTypeResolverBuilder()
.defaultContentType(MediaType.APPLICATION_JSON)
.build();
ServerWebExchange exchange = MockServerHttpRequest.get("/").accept(MediaType.ALL).toExchange();
assertEquals(Collections.singletonList(MediaType.APPLICATION_JSON), resolver.resolveMediaTypes(exchange));
}
@Test // SPR-12286
public void setDefaultContentTypeWithStrategy() throws Exception {
RequestedContentTypeResolver resolver = new RequestedContentTypeResolverBuilder()
.defaultContentTypeResolver(new FixedContentTypeResolver(MediaType.APPLICATION_JSON))
.build();
List<MediaType> expected = Collections.singletonList(MediaType.APPLICATION_JSON);
ServerWebExchange exchange = MockServerHttpRequest.get("/").toExchange();
assertEquals(expected, resolver.resolveMediaTypes(exchange));
exchange = MockServerHttpRequest.get("/").accept(MediaType.ALL).toExchange();
assertEquals(expected, resolver.resolveMediaTypes(exchange));
}
}

103
spring-webflux/src/test/java/org/springframework/web/reactive/accept/MappingContentTypeResolverTests.java

@ -1,103 +0,0 @@ @@ -1,103 +0,0 @@
/*
* Copyright 2002-2017 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.reactive.accept;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.junit.Test;
import org.springframework.http.MediaType;
import org.springframework.lang.Nullable;
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
import org.springframework.web.server.NotAcceptableStatusException;
import org.springframework.web.server.ServerWebExchange;
import static org.junit.Assert.assertEquals;
/**
* Unit tests for {@link AbstractMappingContentTypeResolver}.
* @author Rossen Stoyanchev
*/
public class MappingContentTypeResolverTests {
@Test // SPR-13747
public void resolveCaseInsensitive() {
Map<String, MediaType> mapping = Collections.singletonMap("json", MediaType.APPLICATION_JSON);
TestMappingContentTypeResolver resolver = new TestMappingContentTypeResolver("JSoN", mapping);
List<MediaType> mediaTypes = resolver.resolve();
assertEquals(Collections.singletonList(MediaType.APPLICATION_JSON), mediaTypes);
}
@Test
public void resolveMediaTypes() throws Exception {
Map<String, MediaType> mapping = Collections.singletonMap("json", MediaType.APPLICATION_JSON);
TestMappingContentTypeResolver resolver = new TestMappingContentTypeResolver("json", mapping);
List<MediaType> mediaTypes = resolver.resolve();
assertEquals(1, mediaTypes.size());
assertEquals("application/json", mediaTypes.get(0).toString());
}
@Test
public void resolveNoMatch() throws Exception {
TestMappingContentTypeResolver resolver = new TestMappingContentTypeResolver("blah", Collections.emptyMap());
List<MediaType> mediaTypes = resolver.resolve();
assertEquals(0, mediaTypes.size());
}
@Test
public void resolveNoKey() throws Exception {
Map<String, MediaType> mapping = Collections.singletonMap("json", MediaType.APPLICATION_JSON);
TestMappingContentTypeResolver resolver = new TestMappingContentTypeResolver(null, mapping);
List<MediaType> mediaTypes = resolver.resolve();
assertEquals(0, mediaTypes.size());
}
@Test
public void resolveMediaTypesHandleNoMatch() throws Exception {
TestMappingContentTypeResolver resolver = new TestMappingContentTypeResolver("xml", Collections.emptyMap());
List<MediaType> mediaTypes = resolver.resolve();
assertEquals(1, mediaTypes.size());
assertEquals("application/xml", mediaTypes.get(0).toString());
}
private static class TestMappingContentTypeResolver extends AbstractMappingContentTypeResolver {
private final String key;
TestMappingContentTypeResolver(@Nullable String key, Map<String, MediaType> mapping) {
super(mapping);
this.key = key;
}
public List<MediaType> resolve() throws NotAcceptableStatusException {
return super.resolveMediaTypes(MockServerHttpRequest.get("/").toExchange());
}
@Override
protected String getKey(ServerWebExchange exchange) {
return this.key;
}
}
}

92
spring-webflux/src/test/java/org/springframework/web/reactive/accept/ParameterContentTypeResolverTests.java

@ -0,0 +1,92 @@ @@ -0,0 +1,92 @@
/*
* Copyright 2002-2017 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.reactive.accept;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.junit.Test;
import org.springframework.http.MediaType;
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
import org.springframework.mock.http.server.reactive.test.MockServerWebExchange;
import org.springframework.web.server.NotAcceptableStatusException;
import org.springframework.web.server.ServerWebExchange;
import static org.junit.Assert.assertEquals;
/**
* Unit tests for {@link ParameterContentTypeResolver}.
* @author Rossen Stoyanchev
*/
public class ParameterContentTypeResolverTests {
@Test
public void noKey() throws Exception {
ParameterContentTypeResolver resolver = new ParameterContentTypeResolver(Collections.emptyMap());
List<MediaType> mediaTypes = resolver.resolveMediaTypes(MockServerHttpRequest.get("/").toExchange());
assertEquals(0, mediaTypes.size());
}
@Test(expected = NotAcceptableStatusException.class)
public void noMatchForKey() throws Exception {
ParameterContentTypeResolver resolver = new ParameterContentTypeResolver(Collections.emptyMap());
List<MediaType> mediaTypes = resolver.resolveMediaTypes(createExchange("blah"));
assertEquals(0, mediaTypes.size());
}
@Test
public void resolveKeyFromRegistrations() throws Exception {
ServerWebExchange exchange = createExchange("html");
Map<String, MediaType> mapping = Collections.emptyMap();
RequestedContentTypeResolver resolver = new ParameterContentTypeResolver(mapping);
List<MediaType> mediaTypes = resolver.resolveMediaTypes(exchange);
assertEquals(Collections.singletonList(new MediaType("text", "html")), mediaTypes);
mapping = Collections.singletonMap("HTML", MediaType.APPLICATION_XHTML_XML);
resolver = new ParameterContentTypeResolver(mapping);
mediaTypes = resolver.resolveMediaTypes(exchange);
assertEquals(Collections.singletonList(new MediaType("application", "xhtml+xml")), mediaTypes);
}
@Test
public void resolveKeyThroughMediaTypeFactory() throws Exception {
ServerWebExchange exchange = createExchange("xls");
RequestedContentTypeResolver resolver = new ParameterContentTypeResolver(Collections.emptyMap());
List<MediaType> mediaTypes = resolver.resolveMediaTypes(exchange);
assertEquals(Collections.singletonList(new MediaType("application", "vnd.ms-excel")), mediaTypes);
}
@Test // SPR-13747
public void resolveKeyIsCaseInsensitive() {
ServerWebExchange exchange = createExchange("JSoN");
Map<String, MediaType> mapping = Collections.singletonMap("json", MediaType.APPLICATION_JSON);
ParameterContentTypeResolver resolver = new ParameterContentTypeResolver(mapping);
List<MediaType> mediaTypes = resolver.resolveMediaTypes(exchange);
assertEquals(Collections.singletonList(MediaType.APPLICATION_JSON), mediaTypes);
}
private MockServerWebExchange createExchange(String format) {
return MockServerHttpRequest.get("/path?format=" + format).toExchange();
}
}

83
spring-webflux/src/test/java/org/springframework/web/reactive/accept/PathExtensionContentTypeResolverTests.java

@ -1,83 +0,0 @@ @@ -1,83 +0,0 @@
/*
* Copyright 2002-2017 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.reactive.accept;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.junit.Test;
import org.springframework.http.MediaType;
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
import org.springframework.web.server.ServerWebExchange;
import static org.junit.Assert.assertEquals;
/**
* Unit tests for {@link PathExtensionContentTypeResolver}.
*
* @author Rossen Stoyanchev
*/
public class PathExtensionContentTypeResolverTests {
@Test
public void resolveFromRegistrations() throws Exception {
ServerWebExchange exchange = MockServerHttpRequest.get("/test.html").toExchange();
PathExtensionContentTypeResolver resolver = createResolver();
List<MediaType> mediaTypes = resolver.resolveMediaTypes(exchange);
assertEquals(Collections.singletonList(new MediaType("text", "html")), mediaTypes);
Map<String, MediaType> mapping = Collections.singletonMap("HTML", MediaType.APPLICATION_XHTML_XML);
resolver = new PathExtensionContentTypeResolver(mapping);
mediaTypes = resolver.resolveMediaTypes(exchange);
assertEquals(Collections.singletonList(new MediaType("application", "xhtml+xml")), mediaTypes);
}
@Test
public void resolveFromMediaTypeFactory() throws Exception {
ServerWebExchange exchange = MockServerHttpRequest.get("test.xls").toExchange();
PathExtensionContentTypeResolver resolver = createResolver();
List<MediaType> mediaTypes = resolver.resolveMediaTypes(exchange);
assertEquals(Collections.singletonList(new MediaType("application", "vnd.ms-excel")), mediaTypes);
}
@Test // SPR-9390
public void resolveFromFilenameWithEncodedURI() throws Exception {
ServerWebExchange exchange = MockServerHttpRequest.get("/quo%20vadis%3f.html").toExchange();
PathExtensionContentTypeResolver resolver = createResolver();
List<MediaType> result = resolver.resolveMediaTypes(exchange);
assertEquals("Invalid content type", Collections.singletonList(new MediaType("text", "html")), result);
}
@Test // SPR-10170
public void resolveAndIgnoreUnknownExtension() throws Exception {
ServerWebExchange exchange = MockServerHttpRequest.get("test.foobar").toExchange();
PathExtensionContentTypeResolver resolver = createResolver();
List<MediaType> mediaTypes = resolver.resolveMediaTypes(exchange);
assertEquals(Collections.<MediaType>emptyList(), mediaTypes);
}
private PathExtensionContentTypeResolver createResolver() {
return new PathExtensionContentTypeResolver(Collections.emptyMap());
}
}

100
spring-webflux/src/test/java/org/springframework/web/reactive/accept/RequestedContentTypeResolverBuilderTests.java

@ -0,0 +1,100 @@ @@ -0,0 +1,100 @@
/*
* Copyright 2002-2017 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.reactive.accept;
import java.util.Collections;
import java.util.List;
import org.junit.Test;
import org.springframework.http.MediaType;
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
import org.springframework.web.server.ServerWebExchange;
import static org.junit.Assert.assertEquals;
/**
* Unit tests for {@link RequestedContentTypeResolverBuilder}.
* @author Rossen Stoyanchev
*/
public class RequestedContentTypeResolverBuilderTests {
@Test
public void defaultSettings() throws Exception {
RequestedContentTypeResolver resolver = new RequestedContentTypeResolverBuilder().build();
ServerWebExchange exchange = MockServerHttpRequest.get("/flower").accept(MediaType.IMAGE_GIF).toExchange();
List<MediaType> mediaTypes = resolver.resolveMediaTypes(exchange);
assertEquals(Collections.singletonList(MediaType.IMAGE_GIF), mediaTypes);
}
@Test
public void parameterResolver() throws Exception {
RequestedContentTypeResolverBuilder builder = new RequestedContentTypeResolverBuilder();
builder.parameterResolver().mediaType("json", MediaType.APPLICATION_JSON);
RequestedContentTypeResolver resolver = builder.build();
ServerWebExchange exchange = MockServerHttpRequest.get("/flower?format=json").toExchange();
List<MediaType> mediaTypes = resolver.resolveMediaTypes(exchange);
assertEquals(Collections.singletonList(MediaType.APPLICATION_JSON), mediaTypes);
}
@Test
public void parameterResolverWithCustomParamName() throws Exception {
RequestedContentTypeResolverBuilder builder = new RequestedContentTypeResolverBuilder();
builder.parameterResolver().mediaType("json", MediaType.APPLICATION_JSON).parameterName("s");
RequestedContentTypeResolver resolver = builder.build();
ServerWebExchange exchange = MockServerHttpRequest.get("/flower?s=json").toExchange();
List<MediaType> mediaTypes = resolver.resolveMediaTypes(exchange);
assertEquals(Collections.singletonList(MediaType.APPLICATION_JSON), mediaTypes);
}
@Test // SPR-10513
public void fixedResolver() throws Exception {
RequestedContentTypeResolverBuilder builder = new RequestedContentTypeResolverBuilder();
builder.fixedResolver(MediaType.APPLICATION_JSON);
RequestedContentTypeResolver resolver = builder.build();
ServerWebExchange exchange = MockServerHttpRequest.get("/").accept(MediaType.ALL).toExchange();
List<MediaType> mediaTypes = resolver.resolveMediaTypes(exchange);
assertEquals(Collections.singletonList(MediaType.APPLICATION_JSON), mediaTypes);
}
@Test // SPR-12286
public void resolver() throws Exception {
RequestedContentTypeResolverBuilder builder = new RequestedContentTypeResolverBuilder();
builder.resolver(new FixedContentTypeResolver(MediaType.APPLICATION_JSON));
RequestedContentTypeResolver resolver = builder.build();
ServerWebExchange exchange = MockServerHttpRequest.get("/").toExchange();
List<MediaType> mediaTypes = resolver.resolveMediaTypes(exchange);
assertEquals(Collections.singletonList(MediaType.APPLICATION_JSON), mediaTypes);
exchange = MockServerHttpRequest.get("/").accept(MediaType.ALL).toExchange();
mediaTypes = resolver.resolveMediaTypes(exchange);
assertEquals(Collections.singletonList(MediaType.APPLICATION_JSON), mediaTypes);
}
}

10
spring-webflux/src/test/java/org/springframework/web/reactive/config/WebFluxConfigurationSupportTests.java

@ -40,7 +40,6 @@ import org.springframework.http.codec.ServerCodecConfigurer; @@ -40,7 +40,6 @@ import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.http.codec.json.Jackson2JsonEncoder;
import org.springframework.http.codec.xml.Jaxb2XmlDecoder;
import org.springframework.http.codec.xml.Jaxb2XmlEncoder;
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
import org.springframework.util.MimeType;
import org.springframework.util.MimeTypeUtils;
import org.springframework.util.MultiValueMap;
@ -76,6 +75,7 @@ import static org.springframework.http.MediaType.APPLICATION_OCTET_STREAM; @@ -76,6 +75,7 @@ import static org.springframework.http.MediaType.APPLICATION_OCTET_STREAM;
import static org.springframework.http.MediaType.APPLICATION_XML;
import static org.springframework.http.MediaType.IMAGE_PNG;
import static org.springframework.http.MediaType.TEXT_PLAIN;
import static org.springframework.mock.http.server.reactive.test.MockServerHttpRequest.get;
/**
* Unit tests for {@link WebFluxConfigurationSupport}.
@ -102,12 +102,8 @@ public class WebFluxConfigurationSupportTests { @@ -102,12 +102,8 @@ public class WebFluxConfigurationSupportTests {
RequestedContentTypeResolver resolver = context.getBean(name, RequestedContentTypeResolver.class);
assertSame(resolver, mapping.getContentTypeResolver());
ServerWebExchange exchange = MockServerHttpRequest.get("/path.json").toExchange();
List<MediaType> list = Collections.singletonList(MediaType.APPLICATION_JSON);
assertEquals(list, resolver.resolveMediaTypes(exchange));
exchange = MockServerHttpRequest.get("/path.foobar").toExchange();
assertEquals(Collections.emptyList(), resolver.resolveMediaTypes(exchange));
ServerWebExchange exchange = get("/path").accept(MediaType.APPLICATION_JSON).toExchange();
assertEquals(Collections.singletonList(MediaType.APPLICATION_JSON), resolver.resolveMediaTypes(exchange));
}
@Test

12
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/MessageWriterResultHandlerTests.java

@ -52,11 +52,13 @@ import org.springframework.util.ObjectUtils; @@ -52,11 +52,13 @@ import org.springframework.util.ObjectUtils;
import org.springframework.web.reactive.accept.RequestedContentTypeResolver;
import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder;
import static org.junit.Assert.*;
import static org.springframework.core.io.buffer.support.DataBufferTestUtils.*;
import static org.springframework.http.MediaType.*;
import static org.springframework.web.method.ResolvableMethod.*;
import static org.springframework.web.reactive.HandlerMapping.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.springframework.core.io.buffer.support.DataBufferTestUtils.dumpString;
import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.http.MediaType.APPLICATION_JSON_UTF8;
import static org.springframework.web.method.ResolvableMethod.on;
import static org.springframework.web.reactive.HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE;
/**
* Unit tests for {@link AbstractMessageWriterResultHandler}.

2
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandlerTests.java

@ -29,8 +29,8 @@ import rx.Single; @@ -29,8 +29,8 @@ import rx.Single;
import org.springframework.core.codec.ByteBufferEncoder;
import org.springframework.core.codec.CharSequenceEncoder;
import org.springframework.http.codec.EncoderHttpMessageWriter;
import org.springframework.http.codec.ResourceHttpMessageWriter;
import org.springframework.http.codec.HttpMessageWriter;
import org.springframework.http.codec.ResourceHttpMessageWriter;
import org.springframework.http.codec.json.Jackson2JsonEncoder;
import org.springframework.http.codec.xml.Jaxb2XmlEncoder;
import org.springframework.stereotype.Controller;

2
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ResponseEntityResultHandlerTests.java

@ -44,8 +44,8 @@ import org.springframework.http.HttpHeaders; @@ -44,8 +44,8 @@ import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.codec.EncoderHttpMessageWriter;
import org.springframework.http.codec.ResourceHttpMessageWriter;
import org.springframework.http.codec.HttpMessageWriter;
import org.springframework.http.codec.ResourceHttpMessageWriter;
import org.springframework.http.codec.json.Jackson2JsonEncoder;
import org.springframework.http.codec.xml.Jaxb2XmlEncoder;
import org.springframework.mock.http.server.reactive.test.MockServerWebExchange;

Loading…
Cancel
Save