From c6713c23e327961d021706e5b1e4d5ebe8e2f458 Mon Sep 17 00:00:00 2001 From: Sebastien Deleuze Date: Mon, 2 Nov 2015 12:16:39 +0100 Subject: [PATCH] Add a ResolvableType field to HandlerResult This change allows to be able to check generic type on the return value at HandlerAdapter and ResultHandler level. For example, it allows to do a Publisher check in SimpleHandlerResultHandler. --- .../reactive/web/dispatch/HandlerResult.java | 9 ++- .../dispatch/SimpleHandlerResultHandler.java | 7 +- .../dispatch/handler/HttpHandlerAdapter.java | 5 +- .../RequestMappingHandlerAdapter.java | 4 +- .../annotation/ResponseBodyResultHandler.java | 3 +- .../SimpleHandlerResultHandlerTests.java | 68 +++++++++++++++++++ .../ResponseBodyResultHandlerTests.java | 10 ++- 7 files changed, 96 insertions(+), 10 deletions(-) create mode 100644 spring-web-reactive/src/test/java/org/springframework/reactive/web/dispatch/SimpleHandlerResultHandlerTests.java diff --git a/spring-web-reactive/src/main/java/org/springframework/reactive/web/dispatch/HandlerResult.java b/spring-web-reactive/src/main/java/org/springframework/reactive/web/dispatch/HandlerResult.java index 156f2f5c96..429d688d2a 100644 --- a/spring-web-reactive/src/main/java/org/springframework/reactive/web/dispatch/HandlerResult.java +++ b/spring-web-reactive/src/main/java/org/springframework/reactive/web/dispatch/HandlerResult.java @@ -16,6 +16,7 @@ package org.springframework.reactive.web.dispatch; +import org.springframework.core.ResolvableType; /** * Represent the result of the invocation of an handler. @@ -28,10 +29,13 @@ public class HandlerResult { private final Object value; + private final ResolvableType type; - public HandlerResult(Object handler, Object value) { + + public HandlerResult(Object handler, Object value, ResolvableType type) { this.handler = handler; this.value = value; + this.type = type; } @@ -43,4 +47,7 @@ public class HandlerResult { return this.value; } + public ResolvableType getType() { + return type; + } } diff --git a/spring-web-reactive/src/main/java/org/springframework/reactive/web/dispatch/SimpleHandlerResultHandler.java b/spring-web-reactive/src/main/java/org/springframework/reactive/web/dispatch/SimpleHandlerResultHandler.java index e124bef083..e5dfd544ee 100644 --- a/spring-web-reactive/src/main/java/org/springframework/reactive/web/dispatch/SimpleHandlerResultHandler.java +++ b/spring-web-reactive/src/main/java/org/springframework/reactive/web/dispatch/SimpleHandlerResultHandler.java @@ -22,6 +22,7 @@ import org.reactivestreams.Publisher; import reactor.Publishers; import org.springframework.core.Ordered; +import org.springframework.core.ResolvableType; import org.springframework.http.server.ReactiveServerHttpRequest; import org.springframework.http.server.ReactiveServerHttpResponse; @@ -32,6 +33,8 @@ import org.springframework.http.server.ReactiveServerHttpResponse; */ public class SimpleHandlerResultHandler implements Ordered, HandlerResultHandler { + private static final ResolvableType PUBLISHER_VOID = ResolvableType.forClassWithGenerics(Publisher.class, Void.class); + private int order = Ordered.LOWEST_PRECEDENCE; @@ -46,8 +49,8 @@ public class SimpleHandlerResultHandler implements Ordered, HandlerResultHandler @Override public boolean supports(HandlerResult result) { - Object value = result.getValue(); - return value != null && Publisher.class.isAssignableFrom(value.getClass()); + ResolvableType type = result.getType(); + return type != null && PUBLISHER_VOID.isAssignableFrom(type); } @Override diff --git a/spring-web-reactive/src/main/java/org/springframework/reactive/web/dispatch/handler/HttpHandlerAdapter.java b/spring-web-reactive/src/main/java/org/springframework/reactive/web/dispatch/handler/HttpHandlerAdapter.java index 2204cd85fe..d8190b1428 100644 --- a/spring-web-reactive/src/main/java/org/springframework/reactive/web/dispatch/handler/HttpHandlerAdapter.java +++ b/spring-web-reactive/src/main/java/org/springframework/reactive/web/dispatch/handler/HttpHandlerAdapter.java @@ -19,6 +19,7 @@ package org.springframework.reactive.web.dispatch.handler; import org.reactivestreams.Publisher; import reactor.Publishers; +import org.springframework.core.ResolvableType; import org.springframework.http.server.ReactiveServerHttpRequest; import org.springframework.http.server.ReactiveServerHttpResponse; import org.springframework.reactive.web.dispatch.HandlerAdapter; @@ -38,6 +39,8 @@ import org.springframework.reactive.web.http.HttpHandler; */ public class HttpHandlerAdapter implements HandlerAdapter { + private static final ResolvableType PUBLISHER_VOID = ResolvableType.forClassWithGenerics(Publisher.class, Void.class); + @Override public boolean supports(Object handler) { @@ -50,7 +53,7 @@ public class HttpHandlerAdapter implements HandlerAdapter { HttpHandler httpHandler = (HttpHandler)handler; Publisher completion = httpHandler.handle(request, response); - return Publishers.just(new HandlerResult(httpHandler, completion)); + return Publishers.just(new HandlerResult(httpHandler, completion, PUBLISHER_VOID)); } } diff --git a/spring-web-reactive/src/main/java/org/springframework/reactive/web/dispatch/method/annotation/RequestMappingHandlerAdapter.java b/spring-web-reactive/src/main/java/org/springframework/reactive/web/dispatch/method/annotation/RequestMappingHandlerAdapter.java index 6d3e94e3e6..f840cc5b78 100644 --- a/spring-web-reactive/src/main/java/org/springframework/reactive/web/dispatch/method/annotation/RequestMappingHandlerAdapter.java +++ b/spring-web-reactive/src/main/java/org/springframework/reactive/web/dispatch/method/annotation/RequestMappingHandlerAdapter.java @@ -24,6 +24,7 @@ import org.reactivestreams.Publisher; import reactor.Publishers; import org.springframework.beans.factory.InitializingBean; +import org.springframework.core.ResolvableType; import org.springframework.core.convert.ConversionService; import org.springframework.http.server.ReactiveServerHttpRequest; import org.springframework.http.server.ReactiveServerHttpResponse; @@ -91,9 +92,10 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Initializin InvocableHandlerMethod handlerMethod = new InvocableHandlerMethod((HandlerMethod) handler); handlerMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); + ResolvableType type = ResolvableType.forMethodParameter(handlerMethod.getReturnType()); Publisher resultPublisher = handlerMethod.invokeForRequest(request); - return Publishers.map(resultPublisher, result -> new HandlerResult(handlerMethod, result)); + return Publishers.map(resultPublisher, result -> new HandlerResult(handlerMethod, result, type)); } } \ No newline at end of file diff --git a/spring-web-reactive/src/main/java/org/springframework/reactive/web/dispatch/method/annotation/ResponseBodyResultHandler.java b/spring-web-reactive/src/main/java/org/springframework/reactive/web/dispatch/method/annotation/ResponseBodyResultHandler.java index 9567f7de48..a2d683d7ae 100644 --- a/spring-web-reactive/src/main/java/org/springframework/reactive/web/dispatch/method/annotation/ResponseBodyResultHandler.java +++ b/spring-web-reactive/src/main/java/org/springframework/reactive/web/dispatch/method/annotation/ResponseBodyResultHandler.java @@ -114,8 +114,7 @@ public class ResponseBodyResultHandler implements HandlerResultHandler, Ordered return Publishers.empty(); } - HandlerMethod hm = (HandlerMethod) result.getHandler(); - ResolvableType returnType = ResolvableType.forMethodParameter(hm.getReturnValueType(value)); + ResolvableType returnType = result.getType(); List requestedMediaTypes = getAcceptableMediaTypes(request); List producibleMediaTypes = getProducibleMediaTypes(returnType); diff --git a/spring-web-reactive/src/test/java/org/springframework/reactive/web/dispatch/SimpleHandlerResultHandlerTests.java b/spring-web-reactive/src/test/java/org/springframework/reactive/web/dispatch/SimpleHandlerResultHandlerTests.java new file mode 100644 index 0000000000..fbb7bd2d6d --- /dev/null +++ b/spring-web-reactive/src/test/java/org/springframework/reactive/web/dispatch/SimpleHandlerResultHandlerTests.java @@ -0,0 +1,68 @@ +/* + * Copyright 2002-2015 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.reactive.web.dispatch; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import org.junit.Test; +import org.reactivestreams.Publisher; + +import org.springframework.core.ResolvableType; +import org.springframework.web.method.HandlerMethod; + +/** + * @author Sebastien Deleuze + */ +public class SimpleHandlerResultHandlerTests { + + @Test + public void supports() throws NoSuchMethodException { + + SimpleHandlerResultHandler resultHandler = new SimpleHandlerResultHandler(); + TestController controller = new TestController(); + + HandlerMethod hm = new HandlerMethod(controller, TestController.class.getMethod("voidReturnValue")); + ResolvableType type = ResolvableType.forMethodParameter(hm.getReturnType()); + assertFalse(resultHandler.supports(new HandlerResult(hm, null, type))); + + hm = new HandlerMethod(controller, TestController.class.getMethod("publisherString")); + type = ResolvableType.forMethodParameter(hm.getReturnType()); + assertFalse(resultHandler.supports(new HandlerResult(hm, null, type))); + + hm = new HandlerMethod(controller, TestController.class.getMethod("publisherVoid")); + type = ResolvableType.forMethodParameter(hm.getReturnType()); + assertTrue(resultHandler.supports(new HandlerResult(hm, null, type))); + } + + + @SuppressWarnings("unused") + private static class TestController { + + public Publisher voidReturnValue() { + return null; + } + + public Publisher publisherString() { + return null; + } + + public Publisher publisherVoid() { + return null; + } + } + +} diff --git a/spring-web-reactive/src/test/java/org/springframework/reactive/web/dispatch/method/annotation/ResponseBodyResultHandlerTests.java b/spring-web-reactive/src/test/java/org/springframework/reactive/web/dispatch/method/annotation/ResponseBodyResultHandlerTests.java index ea97ee81a9..7bab9e20ca 100644 --- a/spring-web-reactive/src/test/java/org/springframework/reactive/web/dispatch/method/annotation/ResponseBodyResultHandlerTests.java +++ b/spring-web-reactive/src/test/java/org/springframework/reactive/web/dispatch/method/annotation/ResponseBodyResultHandlerTests.java @@ -21,6 +21,7 @@ import java.util.Collections; import org.junit.Test; import org.reactivestreams.Publisher; +import org.springframework.core.ResolvableType; import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.reactive.codec.encoder.StringEncoder; import org.springframework.reactive.web.dispatch.HandlerResult; @@ -43,13 +44,16 @@ public class ResponseBodyResultHandlerTests { TestController controller = new TestController(); HandlerMethod hm = new HandlerMethod(controller,TestController.class.getMethod("notAnnotated")); - assertFalse(handler.supports(new HandlerResult(hm, null))); + ResolvableType type = ResolvableType.forMethodParameter(hm.getReturnType()); + assertFalse(handler.supports(new HandlerResult(hm, null, type))); hm = new HandlerMethod(controller, TestController.class.getMethod("publisherString")); - assertTrue(handler.supports(new HandlerResult(hm, null))); + type = ResolvableType.forMethodParameter(hm.getReturnType()); + assertTrue(handler.supports(new HandlerResult(hm, null, type))); hm = new HandlerMethod(controller, TestController.class.getMethod("publisherVoid")); - assertTrue(handler.supports(new HandlerResult(hm, null))); + type = ResolvableType.forMethodParameter(hm.getReturnType()); + assertTrue(handler.supports(new HandlerResult(hm, null, type))); }