diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandler.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandler.java index 1fbafc0b41..e0ce99ee1c 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandler.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandler.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}. * - *

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}. + *

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 handleResult(ServerWebExchange exchange, HandlerResult result) { Object body = result.getReturnValue().orElse(null); diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandlerTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandlerTests.java index f2cd44b397..64a576c487 100644 --- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandlerTests.java +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandlerTests.java @@ -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 handleToResponseEntity() { + return null; + } + + public Mono> 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; }