Respect produces condition in @ResponseBody algorithm
This commit is contained in:
@@ -35,15 +35,15 @@ import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.reactive.HttpMessageConverter;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.reactive.HandlerMapping;
|
||||
import org.springframework.web.reactive.HandlerResult;
|
||||
import org.springframework.web.reactive.HandlerResultHandler;
|
||||
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.server.NotAcceptableStatusException;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
@@ -171,11 +171,10 @@ public class ResponseBodyResultHandler implements HandlerResultHandler, Ordered
|
||||
elementType = returnType;
|
||||
}
|
||||
|
||||
ServerHttpRequest request = exchange.getRequest();
|
||||
List<MediaType> compatibleMediaTypes = getCompatibleMediaTypes(exchange, elementType);
|
||||
if (compatibleMediaTypes.isEmpty()) {
|
||||
if (result.getReturnValue().isPresent()) {
|
||||
List<MediaType> mediaTypes = getProducibleMediaTypes(elementType);
|
||||
List<MediaType> mediaTypes = getProducibleMediaTypes(exchange, elementType);
|
||||
return Mono.error(new NotAcceptableStatusException(mediaTypes));
|
||||
}
|
||||
return Mono.empty();
|
||||
@@ -197,13 +196,13 @@ public class ResponseBodyResultHandler implements HandlerResultHandler, Ordered
|
||||
ResolvableType elementType) {
|
||||
|
||||
List<MediaType> acceptableMediaTypes = getAcceptableMediaTypes(exchange);
|
||||
List<MediaType> producibleMediaTypes = getProducibleMediaTypes(elementType);
|
||||
List<MediaType> producibleMediaTypes = getProducibleMediaTypes(exchange, elementType);
|
||||
|
||||
Set<MediaType> compatibleMediaTypes = new LinkedHashSet<>();
|
||||
for (MediaType acceptable : acceptableMediaTypes) {
|
||||
for (MediaType producible : producibleMediaTypes) {
|
||||
if (acceptable.isCompatibleWith(producible)) {
|
||||
compatibleMediaTypes.add(getMostSpecificMediaType(acceptable, producible));
|
||||
compatibleMediaTypes.add(selectMoreSpecificMediaType(acceptable, producible));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -218,19 +217,21 @@ public class ResponseBodyResultHandler implements HandlerResultHandler, Ordered
|
||||
return (mediaTypes.isEmpty() ? Collections.singletonList(MediaType.ALL) : mediaTypes);
|
||||
}
|
||||
|
||||
private List<MediaType> getProducibleMediaTypes(ResolvableType type) {
|
||||
return this.messageConverters.stream()
|
||||
.filter(converter -> converter.canWrite(type, null))
|
||||
.flatMap(converter -> converter.getWritableMediaTypes().stream())
|
||||
.collect(Collectors.collectingAndThen(Collectors.toList(), result -> {
|
||||
if (result.isEmpty()) {
|
||||
result.add(MediaType.ALL);
|
||||
}
|
||||
return result;
|
||||
}));
|
||||
private List<MediaType> getProducibleMediaTypes(ServerWebExchange exchange, ResolvableType type) {
|
||||
Optional<?> optional = exchange.getAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
|
||||
if (optional.isPresent()) {
|
||||
Set<MediaType> mediaTypes = (Set<MediaType>) optional.get();
|
||||
return new ArrayList<>(mediaTypes);
|
||||
}
|
||||
else {
|
||||
return this.messageConverters.stream()
|
||||
.filter(converter -> converter.canWrite(type, null))
|
||||
.flatMap(converter -> converter.getWritableMediaTypes().stream())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
private MediaType getMostSpecificMediaType(MediaType acceptable, MediaType producible) {
|
||||
private MediaType selectMoreSpecificMediaType(MediaType acceptable, MediaType producible) {
|
||||
producible = producible.copyQualityValue(acceptable);
|
||||
Comparator<MediaType> comparator = MediaType.SPECIFICITY_COMPARATOR;
|
||||
return (comparator.compare(acceptable, producible) <= 0 ? acceptable : producible);
|
||||
|
||||
@@ -19,9 +19,13 @@ package org.springframework.web.reactive.result.method.annotation;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.print.attribute.standard.Media;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.reactivestreams.Publisher;
|
||||
|
||||
@@ -40,6 +44,7 @@ import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.ui.ExtendedModelMap;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.reactive.HandlerMapping;
|
||||
import org.springframework.web.reactive.HandlerResult;
|
||||
import org.springframework.web.reactive.HandlerResultHandler;
|
||||
import org.springframework.web.reactive.accept.RequestedContentTypeResolver;
|
||||
@@ -88,7 +93,7 @@ public class ResponseBodyResultHandlerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void contentTypeResolver() throws Exception {
|
||||
public void usesContentTypeResolver() throws Exception {
|
||||
MediaType contentType = MediaType.APPLICATION_JSON_UTF8;
|
||||
RequestedContentTypeResolver resolver = new FixedContentTypeResolver(contentType);
|
||||
HandlerResultHandler handler = createHandler(resolver, new StringEncoder(), new JacksonJsonEncoder());
|
||||
@@ -100,6 +105,20 @@ public class ResponseBodyResultHandlerTests {
|
||||
assertEquals(contentType, exchange.getResponse().getHeaders().getContentType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void detectsProducibleMediaTypesAttribute() throws Exception {
|
||||
ServerWebExchange exchange = createExchange("/foo");
|
||||
Set<MediaType> mediaTypes = Collections.singleton(MediaType.APPLICATION_JSON);
|
||||
exchange.getAttributes().put(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, mediaTypes);
|
||||
|
||||
HandlerResultHandler handler = createHandler(new StringEncoder(), new JacksonJsonEncoder());
|
||||
|
||||
HandlerResult result = new HandlerResult(new Object(), "fooValue", ResolvableType.forClass(String.class));
|
||||
handler.handleResult(exchange, result).get();
|
||||
|
||||
assertEquals(MediaType.APPLICATION_JSON, exchange.getResponse().getHeaders().getContentType());
|
||||
}
|
||||
|
||||
|
||||
private ResponseBodyResultHandler createHandler(Encoder<?>... encoders) {
|
||||
return createHandler(new HeaderContentTypeResolver(), encoders);
|
||||
|
||||
Reference in New Issue
Block a user