Browse Source

Support Model as method argument and in HandlerResult

A model is created and passed to argument resolvers including a new
ModelArgumentResolver. The model is then exposed for result handling
as a field in HandlerResult.
pull/1111/head
Rossen Stoyanchev 10 years ago
parent
commit
14997eccf3
  1. 17
      spring-web-reactive/src/main/java/org/springframework/web/reactive/HandlerResult.java
  2. 5
      spring-web-reactive/src/main/java/org/springframework/web/reactive/handler/HttpHandlerHandlerAdapter.java
  3. 6
      spring-web-reactive/src/main/java/org/springframework/web/reactive/method/HandlerMethodArgumentResolver.java
  4. 14
      spring-web-reactive/src/main/java/org/springframework/web/reactive/method/InvocableHandlerMethod.java
  5. 44
      spring-web-reactive/src/main/java/org/springframework/web/reactive/method/annotation/ModelArgumentResolver.java
  6. 5
      spring-web-reactive/src/main/java/org/springframework/web/reactive/method/annotation/RequestBodyArgumentResolver.java
  7. 12
      spring-web-reactive/src/main/java/org/springframework/web/reactive/method/annotation/RequestMappingHandlerAdapter.java
  8. 3
      spring-web-reactive/src/main/java/org/springframework/web/reactive/method/annotation/RequestParamArgumentResolver.java
  9. 29
      spring-web-reactive/src/test/java/org/springframework/web/reactive/handler/SimpleHandlerResultHandlerTests.java
  10. 27
      spring-web-reactive/src/test/java/org/springframework/web/reactive/method/InvocableHandlerMethodTests.java
  11. 7
      spring-web-reactive/src/test/java/org/springframework/web/reactive/method/annotation/ResponseBodyResultHandlerTests.java

17
spring-web-reactive/src/main/java/org/springframework/web/reactive/HandlerResult.java

@ -22,6 +22,8 @@ import java.util.function.Function; @@ -22,6 +22,8 @@ import java.util.function.Function;
import reactor.core.publisher.Mono;
import org.springframework.core.ResolvableType;
import org.springframework.ui.ExtendedModelMap;
import org.springframework.ui.ModelMap;
import org.springframework.util.Assert;
/**
@ -37,6 +39,8 @@ public class HandlerResult { @@ -37,6 +39,8 @@ public class HandlerResult {
private final ResolvableType returnValueType;
private final ModelMap model;
private Function<Throwable, Mono<HandlerResult>> exceptionHandler;
@ -45,13 +49,16 @@ public class HandlerResult { @@ -45,13 +49,16 @@ public class HandlerResult {
* @param handler the handler that handled the request
* @param returnValue the return value from the handler possibly {@code null}
* @param returnValueType the return value type
* @param model the model used for request handling
*/
public HandlerResult(Object handler, Object returnValue, ResolvableType returnValueType) {
public HandlerResult(Object handler, Object returnValue, ResolvableType returnValueType, ModelMap model) {
Assert.notNull(handler, "'handler' is required");
Assert.notNull(returnValueType, "'returnValueType' is required");
Assert.notNull(model, "'model' is required");
this.handler = handler;
this.returnValue = Optional.ofNullable(returnValue);
this.returnValueType = returnValueType;
this.model = new ExtendedModelMap();
}
@ -76,6 +83,14 @@ public class HandlerResult { @@ -76,6 +83,14 @@ public class HandlerResult {
return this.returnValueType;
}
/**
* Return the model used during request handling with attributes that may be
* used to render HTML templates with.
*/
public ModelMap getModel() {
return this.model;
}
/**
* Configure an exception handler that may be used to produce an alternative
* result when result handling fails. Especially for an async return value

5
spring-web-reactive/src/main/java/org/springframework/web/reactive/handler/HttpHandlerHandlerAdapter.java

@ -20,6 +20,8 @@ import org.reactivestreams.Publisher; @@ -20,6 +20,8 @@ import org.reactivestreams.Publisher;
import reactor.core.publisher.Mono;
import org.springframework.core.ResolvableType;
import org.springframework.ui.ExtendedModelMap;
import org.springframework.ui.ModelMap;
import org.springframework.web.reactive.DispatcherHandler;
import org.springframework.web.reactive.HandlerAdapter;
import org.springframework.web.reactive.HandlerResult;
@ -48,7 +50,8 @@ public class HttpHandlerHandlerAdapter implements HandlerAdapter { @@ -48,7 +50,8 @@ public class HttpHandlerHandlerAdapter implements HandlerAdapter {
public Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler) {
WebHandler webHandler = (WebHandler) handler;
Mono<Void> completion = webHandler.handle(exchange);
return Mono.just(new HandlerResult(webHandler, completion, PUBLISHER_VOID));
ModelMap model = new ExtendedModelMap();
return Mono.just(new HandlerResult(webHandler, completion, PUBLISHER_VOID, model));
}
}

6
spring-web-reactive/src/main/java/org/springframework/web/reactive/method/HandlerMethodArgumentResolver.java

@ -19,6 +19,7 @@ package org.springframework.web.reactive.method; @@ -19,6 +19,7 @@ package org.springframework.web.reactive.method;
import reactor.core.publisher.Mono;
import org.springframework.core.MethodParameter;
import org.springframework.ui.ModelMap;
import org.springframework.web.server.ServerWebExchange;
@ -34,7 +35,10 @@ public interface HandlerMethodArgumentResolver { @@ -34,7 +35,10 @@ public interface HandlerMethodArgumentResolver {
* The returned {@link Mono} may produce one or zero values if the argument
* does not resolve to any value, which will result in {@code null} passed
* as the argument value.
* @param parameter the method parameter
* @param model the implicit model for request handling
* @param exchange the current exchange
*/
Mono<Object> resolveArgument(MethodParameter parameter, ServerWebExchange exchange);
Mono<Object> resolveArgument(MethodParameter parameter, ModelMap model, ServerWebExchange exchange);
}

14
spring-web-reactive/src/main/java/org/springframework/web/reactive/method/InvocableHandlerMethod.java

@ -32,6 +32,7 @@ import org.springframework.core.GenericTypeResolver; @@ -32,6 +32,7 @@ import org.springframework.core.GenericTypeResolver;
import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.ResolvableType;
import org.springframework.ui.ModelMap;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.method.HandlerMethod;
@ -77,17 +78,20 @@ public class InvocableHandlerMethod extends HandlerMethod { @@ -77,17 +78,20 @@ public class InvocableHandlerMethod extends HandlerMethod {
/**
* Invoke the method and return a Publisher for the return value.
* @param exchange the current exchange
* @param model the model for request handling
* @param providedArgs optional list of argument values to check by type
* (via {@code instanceof}) for resolving method arguments.
* @return Publisher that produces a single HandlerResult or an error signal;
* never throws an exception
*/
public Mono<HandlerResult> invokeForRequest(ServerWebExchange exchange, Object... providedArgs) {
return resolveArguments(exchange, providedArgs).then(args -> {
public Mono<HandlerResult> invokeForRequest(ServerWebExchange exchange, ModelMap model,
Object... providedArgs) {
return resolveArguments(exchange, model, providedArgs).then(args -> {
try {
Object value = doInvoke(args);
ResolvableType type = ResolvableType.forMethodParameter(getReturnType());
HandlerResult handlerResult = new HandlerResult(this, value, type);
HandlerResult handlerResult = new HandlerResult(this, value, type, model);
return Mono.just(handlerResult);
}
catch (InvocationTargetException ex) {
@ -100,7 +104,7 @@ public class InvocableHandlerMethod extends HandlerMethod { @@ -100,7 +104,7 @@ public class InvocableHandlerMethod extends HandlerMethod {
});
}
private Mono<Object[]> resolveArguments(ServerWebExchange exchange, Object... providedArgs) {
private Mono<Object[]> resolveArguments(ServerWebExchange exchange, ModelMap model, Object... providedArgs) {
if (ObjectUtils.isEmpty(getMethodParameters())) {
return NO_ARGS;
}
@ -121,7 +125,7 @@ public class InvocableHandlerMethod extends HandlerMethod { @@ -121,7 +125,7 @@ public class InvocableHandlerMethod extends HandlerMethod {
.findFirst()
.orElseThrow(() -> getArgError("No resolver for ", param, null));
try {
return resolver.resolveArgument(param, exchange)
return resolver.resolveArgument(param, model, exchange)
.defaultIfEmpty(NO_VALUE)
.otherwise(ex -> Mono.error(getArgError("Error resolving ", param, ex)))
.log("reactor.unresolved");

44
spring-web-reactive/src/main/java/org/springframework/web/reactive/method/annotation/ModelArgumentResolver.java

@ -0,0 +1,44 @@ @@ -0,0 +1,44 @@
/*
* Copyright 2002-2016 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.web.reactive.method.annotation;
import reactor.core.publisher.Mono;
import org.springframework.core.MethodParameter;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.reactive.method.HandlerMethodArgumentResolver;
import org.springframework.web.server.ServerWebExchange;
/**
* Resolver for the {@link Model} controller method argument.
*
* @author Rossen Stoyanchev
*/
public class ModelArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return Model.class.isAssignableFrom(parameter.getParameterType());
}
@Override
public Mono<Object> resolveArgument(MethodParameter parameter, ModelMap model, ServerWebExchange exchange) {
return Mono.just(model);
}
}

5
spring-web-reactive/src/main/java/org/springframework/web/reactive/method/annotation/RequestBodyArgumentResolver.java

@ -28,6 +28,7 @@ import org.springframework.core.codec.Decoder; @@ -28,6 +28,7 @@ import org.springframework.core.codec.Decoder;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.MediaType;
import org.springframework.ui.ModelMap;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.reactive.method.HandlerMethodArgumentResolver;
@ -58,7 +59,9 @@ public class RequestBodyArgumentResolver implements HandlerMethodArgumentResolve @@ -58,7 +59,9 @@ public class RequestBodyArgumentResolver implements HandlerMethodArgumentResolve
}
@Override
public Mono<Object> resolveArgument(MethodParameter parameter, ServerWebExchange exchange) {
public Mono<Object> resolveArgument(MethodParameter parameter, ModelMap model,
ServerWebExchange exchange) {
MediaType mediaType = exchange.getRequest().getHeaders().getContentType();
if (mediaType == null) {
mediaType = MediaType.APPLICATION_OCTET_STREAM;

12
spring-web-reactive/src/main/java/org/springframework/web/reactive/method/annotation/RequestMappingHandlerAdapter.java

@ -38,6 +38,8 @@ import org.springframework.core.convert.ConversionService; @@ -38,6 +38,8 @@ import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.io.buffer.DataBufferAllocator;
import org.springframework.core.io.buffer.NettyDataBufferAllocator;
import org.springframework.ui.ExtendedModelMap;
import org.springframework.ui.ModelMap;
import org.springframework.util.ObjectUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.method.annotation.ExceptionHandlerMethodResolver;
@ -64,7 +66,7 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Initializin @@ -64,7 +66,7 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Initializin
new NettyDataBufferAllocator(new UnpooledByteBufAllocator(false));
private final Map<Class<?>, ExceptionHandlerMethodResolver> exceptionHandlerCache =
new ConcurrentHashMap<Class<?>, ExceptionHandlerMethodResolver>(64);
new ConcurrentHashMap<>(64);
/**
@ -105,6 +107,7 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Initializin @@ -105,6 +107,7 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Initializin
this.argumentResolvers.add(new RequestParamArgumentResolver());
this.argumentResolvers.add(new RequestBodyArgumentResolver(decoders, this.conversionService));
this.argumentResolvers.add(new ModelArgumentResolver());
}
}
@ -118,8 +121,8 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Initializin @@ -118,8 +121,8 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Initializin
HandlerMethod handlerMethod = (HandlerMethod) handler;
InvocableHandlerMethod invocable = new InvocableHandlerMethod(handlerMethod);
invocable.setHandlerMethodArgumentResolvers(this.argumentResolvers);
return invocable.invokeForRequest(exchange)
ModelMap model = new ExtendedModelMap();
return invocable.invokeForRequest(exchange, model)
.map(result -> result.setExceptionHandler(ex -> handleException(ex, handlerMethod, exchange)))
.otherwise(ex -> handleException(ex, handlerMethod, exchange));
}
@ -135,7 +138,8 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Initializin @@ -135,7 +138,8 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Initializin
logger.debug("Invoking @ExceptionHandler method: " + invocable);
}
invocable.setHandlerMethodArgumentResolvers(getArgumentResolvers());
return invocable.invokeForRequest(exchange, ex);
ExtendedModelMap errorModel = new ExtendedModelMap();
return invocable.invokeForRequest(exchange, errorModel, ex);
}
catch (Exception invocationEx) {
if (logger.isErrorEnabled()) {

3
spring-web-reactive/src/main/java/org/springframework/web/reactive/method/annotation/RequestParamArgumentResolver.java

@ -19,6 +19,7 @@ package org.springframework.web.reactive.method.annotation; @@ -19,6 +19,7 @@ package org.springframework.web.reactive.method.annotation;
import reactor.core.publisher.Mono;
import org.springframework.core.MethodParameter;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.reactive.method.HandlerMethodArgumentResolver;
import org.springframework.web.server.ServerWebExchange;
@ -41,7 +42,7 @@ public class RequestParamArgumentResolver implements HandlerMethodArgumentResolv @@ -41,7 +42,7 @@ public class RequestParamArgumentResolver implements HandlerMethodArgumentResolv
@Override
public Mono<Object> resolveArgument(MethodParameter param, ServerWebExchange exchange) {
public Mono<Object> resolveArgument(MethodParameter param, ModelMap model, ServerWebExchange exchange) {
RequestParam annotation = param.getParameterAnnotation(RequestParam.class);
String name = (annotation.value().length() != 0 ? annotation.value() : param.getParameterName());
UriComponents uriComponents = UriComponentsBuilder.fromUri(exchange.getRequest().getURI()).build();

29
spring-web-reactive/src/test/java/org/springframework/web/reactive/handler/SimpleHandlerResultHandlerTests.java

@ -30,6 +30,7 @@ import org.springframework.core.convert.support.GenericConversionService; @@ -30,6 +30,7 @@ import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.core.convert.support.ReactiveStreamsToCompletableFutureConverter;
import org.springframework.core.convert.support.ReactiveStreamsToReactorStreamConverter;
import org.springframework.core.convert.support.ReactiveStreamsToRxJava1Converter;
import org.springframework.ui.ExtendedModelMap;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.reactive.HandlerResult;
@ -46,28 +47,28 @@ public class SimpleHandlerResultHandlerTests { @@ -46,28 +47,28 @@ public class SimpleHandlerResultHandlerTests {
HandlerMethod hm = new HandlerMethod(controller, TestController.class.getMethod("voidReturnValue"));
ResolvableType type = ResolvableType.forMethodParameter(hm.getReturnType());
assertTrue(resultHandler.supports(new HandlerResult(hm, null, type)));
assertTrue(resultHandler.supports(createHandlerResult(hm, type)));
hm = new HandlerMethod(controller, TestController.class.getMethod("publisherString"));
type = ResolvableType.forMethodParameter(hm.getReturnType());
assertFalse(resultHandler.supports(new HandlerResult(hm, null, type)));
assertFalse(resultHandler.supports(createHandlerResult(hm, type)));
hm = new HandlerMethod(controller, TestController.class.getMethod("publisherVoid"));
type = ResolvableType.forMethodParameter(hm.getReturnType());
assertTrue(resultHandler.supports(new HandlerResult(hm, null, type)));
assertTrue(resultHandler.supports(createHandlerResult(hm, type)));
hm = new HandlerMethod(controller, TestController.class.getMethod("streamVoid"));
type = ResolvableType.forMethodParameter(hm.getReturnType());
// Reactor Stream is a Publisher
assertTrue(resultHandler.supports(new HandlerResult(hm, null, type)));
assertTrue(resultHandler.supports(createHandlerResult(hm, type)));
hm = new HandlerMethod(controller, TestController.class.getMethod("observableVoid"));
type = ResolvableType.forMethodParameter(hm.getReturnType());
assertFalse(resultHandler.supports(new HandlerResult(hm, null, type)));
assertFalse(resultHandler.supports(createHandlerResult(hm, type)));
hm = new HandlerMethod(controller, TestController.class.getMethod("completableFutureVoid"));
type = ResolvableType.forMethodParameter(hm.getReturnType());
assertFalse(resultHandler.supports(new HandlerResult(hm, null, type)));
assertFalse(resultHandler.supports(createHandlerResult(hm, type)));
}
@Test
@ -82,27 +83,31 @@ public class SimpleHandlerResultHandlerTests { @@ -82,27 +83,31 @@ public class SimpleHandlerResultHandlerTests {
HandlerMethod hm = new HandlerMethod(controller, TestController.class.getMethod("voidReturnValue"));
ResolvableType type = ResolvableType.forMethodParameter(hm.getReturnType());
assertTrue(resultHandler.supports(new HandlerResult(hm, null, type)));
assertTrue(resultHandler.supports(createHandlerResult(hm, type)));
hm = new HandlerMethod(controller, TestController.class.getMethod("publisherString"));
type = ResolvableType.forMethodParameter(hm.getReturnType());
assertFalse(resultHandler.supports(new HandlerResult(hm, null, type)));
assertFalse(resultHandler.supports(createHandlerResult(hm, type)));
hm = new HandlerMethod(controller, TestController.class.getMethod("publisherVoid"));
type = ResolvableType.forMethodParameter(hm.getReturnType());
assertTrue(resultHandler.supports(new HandlerResult(hm, null, type)));
assertTrue(resultHandler.supports(createHandlerResult(hm, type)));
hm = new HandlerMethod(controller, TestController.class.getMethod("streamVoid"));
type = ResolvableType.forMethodParameter(hm.getReturnType());
assertTrue(resultHandler.supports(new HandlerResult(hm, null, type)));
assertTrue(resultHandler.supports(createHandlerResult(hm, type)));
hm = new HandlerMethod(controller, TestController.class.getMethod("observableVoid"));
type = ResolvableType.forMethodParameter(hm.getReturnType());
assertTrue(resultHandler.supports(new HandlerResult(hm, null, type)));
assertTrue(resultHandler.supports(createHandlerResult(hm, type)));
hm = new HandlerMethod(controller, TestController.class.getMethod("completableFutureVoid"));
type = ResolvableType.forMethodParameter(hm.getReturnType());
assertTrue(resultHandler.supports(new HandlerResult(hm, null, type)));
assertTrue(resultHandler.supports(createHandlerResult(hm, type)));
}
private HandlerResult createHandlerResult(HandlerMethod hm, ResolvableType type) {
return new HandlerResult(hm, null, type, new ExtendedModelMap());
}

27
spring-web-reactive/src/test/java/org/springframework/web/reactive/method/InvocableHandlerMethodTests.java

@ -31,6 +31,8 @@ import reactor.rx.Stream; @@ -31,6 +31,8 @@ import reactor.rx.Stream;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.ui.ExtendedModelMap;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.reactive.HandlerResult;
@ -54,12 +56,15 @@ public class InvocableHandlerMethodTests { @@ -54,12 +56,15 @@ public class InvocableHandlerMethodTests {
private ServerWebExchange exchange;
private ModelMap model;
@Before
public void setUp() throws Exception {
WebSessionManager sessionManager = mock(WebSessionManager.class);
this.request = mock(ServerHttpRequest.class);
this.exchange = new DefaultServerWebExchange(request, mock(ServerHttpResponse.class), sessionManager);
this.model = new ExtendedModelMap();
}
@ -67,7 +72,7 @@ public class InvocableHandlerMethodTests { @@ -67,7 +72,7 @@ public class InvocableHandlerMethodTests {
public void noArgsMethod() throws Exception {
InvocableHandlerMethod hm = createHandlerMethod("noArgs");
Publisher<HandlerResult> publisher = hm.invokeForRequest(this.exchange);
Publisher<HandlerResult> publisher = hm.invokeForRequest(this.exchange, this.model);
List<HandlerResult> values = Stream.from(publisher).toList().get();
assertEquals(1, values.size());
@ -80,7 +85,7 @@ public class InvocableHandlerMethodTests { @@ -80,7 +85,7 @@ public class InvocableHandlerMethodTests {
InvocableHandlerMethod hm = createHandlerMethod("singleArg", String.class);
hm.setHandlerMethodArgumentResolvers(Collections.singletonList(new RequestParamArgumentResolver()));
Publisher<HandlerResult> publisher = hm.invokeForRequest(this.exchange);
Publisher<HandlerResult> publisher = hm.invokeForRequest(this.exchange, this.model);
List<HandlerResult> values = Stream.from(publisher).toList().get();
assertEquals(1, values.size());
@ -92,7 +97,7 @@ public class InvocableHandlerMethodTests { @@ -92,7 +97,7 @@ public class InvocableHandlerMethodTests {
InvocableHandlerMethod hm = createHandlerMethod("singleArg", String.class);
addResolver(hm, Mono.just("value1"));
Publisher<HandlerResult> publisher = hm.invokeForRequest(this.exchange);
Publisher<HandlerResult> publisher = hm.invokeForRequest(this.exchange, this.model);
List<HandlerResult> values = Stream.from(publisher).toList().get();
assertEquals(1, values.size());
@ -104,7 +109,7 @@ public class InvocableHandlerMethodTests { @@ -104,7 +109,7 @@ public class InvocableHandlerMethodTests {
InvocableHandlerMethod hm = createHandlerMethod("singleArg", String.class);
addResolver(hm, Flux.fromIterable(Arrays.asList("value1", "value2", "value3")));
Publisher<HandlerResult> publisher = hm.invokeForRequest(this.exchange);
Publisher<HandlerResult> publisher = hm.invokeForRequest(this.exchange, this.model);
List<HandlerResult> values = Stream.from(publisher).toList().get();
assertEquals(1, values.size());
@ -115,7 +120,7 @@ public class InvocableHandlerMethodTests { @@ -115,7 +120,7 @@ public class InvocableHandlerMethodTests {
public void noResolverForArg() throws Exception {
InvocableHandlerMethod hm = createHandlerMethod("singleArg", String.class);
Publisher<HandlerResult> publisher = hm.invokeForRequest(this.exchange);
Publisher<HandlerResult> publisher = hm.invokeForRequest(this.exchange, this.model);
Throwable ex = awaitErrorSignal(publisher);
assertEquals(IllegalStateException.class, ex.getClass());
@ -127,12 +132,12 @@ public class InvocableHandlerMethodTests { @@ -127,12 +132,12 @@ public class InvocableHandlerMethodTests {
public void resolveArgumentWithThrownException() throws Exception {
HandlerMethodArgumentResolver resolver = mock(HandlerMethodArgumentResolver.class);
when(resolver.supportsParameter(any())).thenReturn(true);
when(resolver.resolveArgument(any(), any())).thenThrow(new IllegalStateException("boo"));
when(resolver.resolveArgument(any(), any(), any())).thenThrow(new IllegalStateException("boo"));
InvocableHandlerMethod hm = createHandlerMethod("singleArg", String.class);
hm.setHandlerMethodArgumentResolvers(Collections.singletonList(resolver));
Publisher<HandlerResult> publisher = hm.invokeForRequest(this.exchange);
Publisher<HandlerResult> publisher = hm.invokeForRequest(this.exchange, this.model);
Throwable ex = awaitErrorSignal(publisher);
assertEquals(IllegalStateException.class, ex.getClass());
@ -146,7 +151,7 @@ public class InvocableHandlerMethodTests { @@ -146,7 +151,7 @@ public class InvocableHandlerMethodTests {
InvocableHandlerMethod hm = createHandlerMethod("singleArg", String.class);
addResolver(hm, Mono.error(new IllegalStateException("boo")));
Publisher<HandlerResult> publisher = hm.invokeForRequest(this.exchange);
Publisher<HandlerResult> publisher = hm.invokeForRequest(this.exchange, this.model);
Throwable ex = awaitErrorSignal(publisher);
assertEquals(IllegalStateException.class, ex.getClass());
@ -160,7 +165,7 @@ public class InvocableHandlerMethodTests { @@ -160,7 +165,7 @@ public class InvocableHandlerMethodTests {
InvocableHandlerMethod hm = createHandlerMethod("singleArg", String.class);
addResolver(hm, Mono.just(1));
Publisher<HandlerResult> publisher = hm.invokeForRequest(this.exchange);
Publisher<HandlerResult> publisher = hm.invokeForRequest(this.exchange, this.model);
Throwable ex = awaitErrorSignal(publisher);
assertEquals(IllegalStateException.class, ex.getClass());
@ -173,7 +178,7 @@ public class InvocableHandlerMethodTests { @@ -173,7 +178,7 @@ public class InvocableHandlerMethodTests {
public void invocationTargetExceptionIsUnwrapped() throws Exception {
InvocableHandlerMethod hm = createHandlerMethod("exceptionMethod");
Publisher<HandlerResult> publisher = hm.invokeForRequest(this.exchange);
Publisher<HandlerResult> publisher = hm.invokeForRequest(this.exchange, this.model);
Throwable ex = awaitErrorSignal(publisher);
assertEquals(IllegalStateException.class, ex.getClass());
@ -190,7 +195,7 @@ public class InvocableHandlerMethodTests { @@ -190,7 +195,7 @@ public class InvocableHandlerMethodTests {
private void addResolver(InvocableHandlerMethod handlerMethod, Publisher<Object> resolvedValue) {
HandlerMethodArgumentResolver resolver = mock(HandlerMethodArgumentResolver.class);
when(resolver.supportsParameter(any())).thenReturn(true);
when(resolver.resolveArgument(any(), any())).thenReturn(Mono.from(resolvedValue));
when(resolver.resolveArgument(any(), any(), any())).thenReturn(Mono.from(resolvedValue));
handlerMethod.setHandlerMethodArgumentResolvers(Collections.singletonList(resolver));
}

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

@ -25,6 +25,7 @@ import org.springframework.core.ResolvableType; @@ -25,6 +25,7 @@ import org.springframework.core.ResolvableType;
import org.springframework.core.codec.support.StringEncoder;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.io.buffer.DefaultDataBufferAllocator;
import org.springframework.ui.ExtendedModelMap;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.reactive.HandlerResult;
@ -47,15 +48,15 @@ public class ResponseBodyResultHandlerTests { @@ -47,15 +48,15 @@ public class ResponseBodyResultHandlerTests {
HandlerMethod hm = new HandlerMethod(controller,TestController.class.getMethod("notAnnotated"));
ResolvableType type = ResolvableType.forMethodParameter(hm.getReturnType());
assertFalse(handler.supports(new HandlerResult(hm, null, type)));
assertFalse(handler.supports(new HandlerResult(hm, null, type, new ExtendedModelMap())));
hm = new HandlerMethod(controller, TestController.class.getMethod("publisherString"));
type = ResolvableType.forMethodParameter(hm.getReturnType());
assertTrue(handler.supports(new HandlerResult(hm, null, type)));
assertTrue(handler.supports(new HandlerResult(hm, null, type, new ExtendedModelMap())));
hm = new HandlerMethod(controller, TestController.class.getMethod("publisherVoid"));
type = ResolvableType.forMethodParameter(hm.getReturnType());
assertTrue(handler.supports(new HandlerResult(hm, null, type)));
assertTrue(handler.supports(new HandlerResult(hm, null, type, new ExtendedModelMap())));
}

Loading…
Cancel
Save