ResponseBodyResultHandler ignores ResponseEntity

Currently ResponseEntityResultHandler is ordered lower than
ResponseBodyResultHandler by default whch means a ResponseEntity
should not be picked by the ResponseBodyResultHandler.

However as it is easy to have both ResponseEntity and @ResponseBody
e.g. in @RestControler (or even by mistake) and in general it makes
sense for ResponseBodyResultHandler to explicitly recognize and
ignore the ResponseEntity return type.
master
Rossen Stoyanchev 8 years ago
parent c24b504a07
commit 699b057126
  1. 42
      spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandler.java
  2. 29
      spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandlerTests.java

@ -24,9 +24,9 @@ import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.convert.ConversionService;
import org.springframework.http.HttpEntity;
import org.springframework.http.converter.reactive.HttpMessageConverter;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.reactive.HandlerResult;
import org.springframework.web.reactive.HandlerResultHandler;
import org.springframework.web.reactive.accept.HeaderContentTypeResolver;
@ -39,10 +39,10 @@ import org.springframework.web.server.ServerWebExchange;
* with {@code @ResponseBody} writing to the body of the request or response with
* an {@link HttpMessageConverter}.
*
* <p>By default the order for the result handler is set to 100. It detects the
* presence of an {@code @ResponseBody} annotation and should be ordered after
* result handlers that look for a specific return type such as
* {@code ResponseEntity}.
* <p>By default the order for this result handler is set to 100. As it detects
* the presence of {@code @ResponseBody} it should be ordered after result
* handlers that look for a specific return type. Note however that this handler
* does recognize and explicitly ignores the {@code ResponseEntity} return type.
*
* @author Rossen Stoyanchev
* @author Stephane Maldini
@ -85,16 +85,36 @@ public class ResponseBodyResultHandler extends AbstractMessageConverterResultHan
@Override
public boolean supports(HandlerResult result) {
Object handler = result.getHandler();
if (handler instanceof HandlerMethod) {
MethodParameter returnType = ((HandlerMethod) handler).getReturnType();
Class<?> containingClass = returnType.getContainingClass();
return (AnnotationUtils.findAnnotation(containingClass, ResponseBody.class) != null ||
returnType.getMethodAnnotation(ResponseBody.class) != null);
ResolvableType returnType = result.getReturnValueType();
if (returnType.getSource() instanceof MethodParameter) {
MethodParameter parameter = (MethodParameter) returnType.getSource();
if (hasResponseBodyAnnotation(parameter) && !isHttpEntityType(returnType)) {
return true;
}
}
return false;
}
private boolean hasResponseBodyAnnotation(MethodParameter parameter) {
Class<?> containingClass = parameter.getContainingClass();
return (AnnotationUtils.findAnnotation(containingClass, ResponseBody.class) != null ||
parameter.getMethodAnnotation(ResponseBody.class) != null);
}
private boolean isHttpEntityType(ResolvableType returnType) {
if (HttpEntity.class.isAssignableFrom(returnType.getRawClass())) {
return true;
}
else if (getConversionService().canConvert(returnType.getRawClass(), Mono.class)) {
ResolvableType genericType = returnType.getGeneric(0);
if (HttpEntity.class.isAssignableFrom(genericType.getRawClass())) {
return true;
}
}
return false;
}
@Override
public Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {
Object body = result.getReturnValue().orElse(null);

@ -23,6 +23,7 @@ import java.util.List;
import org.junit.Before;
import org.junit.Test;
import reactor.core.publisher.Mono;
import org.springframework.core.ResolvableType;
import org.springframework.core.codec.support.ByteBufferEncoder;
@ -34,6 +35,7 @@ import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.core.convert.support.ReactiveStreamsToCompletableFutureConverter;
import org.springframework.core.convert.support.ReactiveStreamsToRxJava1Converter;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.reactive.CodecHttpMessageConverter;
import org.springframework.http.converter.reactive.HttpMessageConverter;
import org.springframework.http.converter.reactive.ResourceHttpMessageConverter;
@ -108,14 +110,14 @@ public class ResponseBodyResultHandlerTests {
@Test
public void supports() throws NoSuchMethodException {
TestController controller = new TestController();
testSupports(controller, "handleReturningString", true);
testSupports(controller, "handleReturningVoid", true);
Object controller = new TestController();
testSupports(controller, "handleToString", true);
testSupports(controller, "doWork", false);
TestRestController restController = new TestRestController();
testSupports(restController, "handleReturningString", true);
testSupports(restController, "handleReturningVoid", true);
controller = new TestRestController();
testSupports(controller, "handleToString", true);
testSupports(controller, "handleToResponseEntity", false);
testSupports(controller, "handleToMonoResponseEntity", false);
}
private void testSupports(Object controller, String method, boolean result) throws NoSuchMethodException {
@ -139,11 +141,15 @@ public class ResponseBodyResultHandlerTests {
@RestController @SuppressWarnings("unused")
private static class TestRestController {
public String handleReturningString() {
public String handleToString() {
return null;
}
public Void handleReturningVoid() {
public ResponseEntity<String> handleToResponseEntity() {
return null;
}
public Mono<ResponseEntity<String>> handleToMonoResponseEntity() {
return null;
}
}
@ -152,12 +158,7 @@ public class ResponseBodyResultHandlerTests {
private static class TestController {
@ResponseBody
public String handleReturningString() {
return null;
}
@ResponseBody
public Void handleReturningVoid() {
public String handleToString() {
return null;
}

Loading…
Cancel
Save