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.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user