Browse Source

Respect produces condition in @ResponseBody algorithm

pull/1111/head
Rossen Stoyanchev 10 years ago
parent
commit
2263954ad7
  1. 35
      spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandler.java
  2. 21
      spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandlerTests.java

35
spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandler.java

@ -35,15 +35,15 @@ import org.springframework.core.annotation.AnnotationUtils; @@ -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 @@ -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 @@ -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 @@ -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);

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

@ -19,9 +19,13 @@ package org.springframework.web.reactive.result.method.annotation; @@ -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; @@ -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 { @@ -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 { @@ -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);

Loading…
Cancel
Save