Update HandlerResult

Rename result to returnValue and resultType to returnValueType to
reflect what they represent.

The returnValue getter is also wrapped as Optional since the value
returned from a handler may be null (e.g. void method, null value).
This commit is contained in:
Rossen Stoyanchev 2016-02-02 11:40:49 -05:00
parent b7b423a003
commit e92174c772
5 changed files with 62 additions and 34 deletions

View File

@ -146,7 +146,7 @@ public class DispatcherHandler implements WebHandler, ApplicationContextAware {
return resultHandler; return resultHandler;
} }
} }
throw new IllegalStateException("No HandlerResultHandler for " + handlerResult.getResult()); throw new IllegalStateException("No HandlerResultHandler for " + handlerResult.getReturnValue());
} }

View File

@ -16,6 +16,7 @@
package org.springframework.web.reactive; package org.springframework.web.reactive;
import java.util.Optional;
import java.util.function.Function; import java.util.function.Function;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
@ -32,40 +33,54 @@ public class HandlerResult {
private final Object handler; private final Object handler;
private final Object result; private final Optional<Object> returnValue;
private final ResolvableType resultType; private final ResolvableType returnValueType;
private Function<Throwable, Mono<HandlerResult>> exceptionHandler; private Function<Throwable, Mono<HandlerResult>> exceptionHandler;
public HandlerResult(Object handler, Object result, ResolvableType resultType) { /**
* Create a new {@code 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
*/
public HandlerResult(Object handler, Object returnValue, ResolvableType returnValueType) {
Assert.notNull(handler, "'handler' is required"); Assert.notNull(handler, "'handler' is required");
Assert.notNull(handler, "'resultType' is required"); Assert.notNull(returnValueType, "'returnValueType' is required");
this.handler = handler; this.handler = handler;
this.result = result; this.returnValue = Optional.ofNullable(returnValue);
this.resultType = resultType; this.returnValueType = returnValueType;
} }
/**
* Return the handler that handled the request.
*/
public Object getHandler() { public Object getHandler() {
return this.handler; return this.handler;
} }
public Object getResult() { /**
return this.result; * Return the value returned from the handler wrapped as {@link Optional}.
} */
public Optional<Object> getReturnValue() {
public ResolvableType getResultType() { return this.returnValue;
return this.resultType;
} }
/** /**
* For an async result, failures may occur later during result handling. * Return the type of the value returned from the handler.
* Use this property to configure an exception handler to be invoked if */
* result handling fails. public ResolvableType getReturnValueType() {
* return this.returnValueType;
* @param function a function to map the the error to an alternative result. }
/**
* Configure an exception handler that may be used to produce an alternative
* result when result handling fails. Especially for an async return value
* errors may occur after the invocation of the handler.
* @param function the error handler
* @return the current instance * @return the current instance
*/ */
public HandlerResult setExceptionHandler(Function<Throwable, Mono<HandlerResult>> function) { public HandlerResult setExceptionHandler(Function<Throwable, Mono<HandlerResult>> function) {
@ -73,12 +88,20 @@ public class HandlerResult {
return this; return this;
} }
/**
* Whether there is an exception handler.
*/
public boolean hasExceptionHandler() { public boolean hasExceptionHandler() {
return (this.exceptionHandler != null); return (this.exceptionHandler != null);
} }
public Mono<HandlerResult> applyExceptionHandler(Throwable ex) { /**
return (hasExceptionHandler() ? this.exceptionHandler.apply(ex) : Mono.error(ex)); * Apply the exception handler and return the alternative result.
* @param failure the exception
* @return the new result or the same error if there is no exception handler
*/
public Mono<HandlerResult> applyExceptionHandler(Throwable failure) {
return (hasExceptionHandler() ? this.exceptionHandler.apply(failure) : Mono.error(failure));
} }
} }

View File

@ -16,6 +16,8 @@
package org.springframework.web.reactive.handler; package org.springframework.web.reactive.handler;
import java.util.Optional;
import org.reactivestreams.Publisher; import org.reactivestreams.Publisher;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
@ -61,7 +63,7 @@ public class SimpleHandlerResultHandler implements Ordered, HandlerResultHandler
@Override @Override
public boolean supports(HandlerResult result) { public boolean supports(HandlerResult result) {
ResolvableType type = result.getResultType(); ResolvableType type = result.getReturnValueType();
return (type != null && Void.TYPE.equals(type.getRawClass()) || return (type != null && Void.TYPE.equals(type.getRawClass()) ||
(isConvertibleToPublisher(type) && Void.class.isAssignableFrom(type.getGeneric(0).getRawClass()))); (isConvertibleToPublisher(type) && Void.class.isAssignableFrom(type.getGeneric(0).getRawClass())));
} }
@ -75,12 +77,14 @@ public class SimpleHandlerResultHandler implements Ordered, HandlerResultHandler
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) { public Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {
Object value = result.getResult(); Optional<Object> value = result.getReturnValue();
if (Void.TYPE.equals(result.getResultType().getRawClass())) { if (!value.isPresent() || Void.TYPE.equals(result.getReturnValueType().getRawClass())) {
return Mono.empty(); return Mono.empty();
} }
return (value instanceof Mono ? (Mono<Void>)value : if (value.get() instanceof Mono) {
Mono.from(this.conversionService.convert(value, Publisher.class))); return (Mono<Void>) value.get();
}
return Mono.from(this.conversionService.convert(value.get(), Publisher.class));
} }
} }

View File

@ -23,6 +23,7 @@ import java.util.HashMap;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -132,23 +133,23 @@ public class ResponseBodyResultHandler implements HandlerResultHandler, Ordered
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) { public Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {
Object value = result.getResult(); Optional<Object> value = result.getReturnValue();
if (value == null) { if (!value.isPresent()) {
return Mono.empty(); return Mono.empty();
} }
Publisher<?> publisher; Publisher<?> publisher;
ResolvableType elementType; ResolvableType elementType;
ResolvableType returnType = result.getResultType(); ResolvableType returnType = result.getReturnValueType();
if (this.conversionService.canConvert(returnType.getRawClass(), Publisher.class)) { if (this.conversionService.canConvert(returnType.getRawClass(), Publisher.class)) {
publisher = this.conversionService.convert(value, Publisher.class); publisher = this.conversionService.convert(value.get(), Publisher.class);
elementType = returnType.getGeneric(0); elementType = returnType.getGeneric(0);
if (Void.class.equals(elementType.getRawClass())) { if (Void.class.equals(elementType.getRawClass())) {
return (Mono<Void>)Mono.from(publisher); return (Mono<Void>)Mono.from(publisher);
} }
} }
else { else {
publisher = Mono.just(value); publisher = Mono.just(value.get());
elementType = returnType; elementType = returnType;
} }

View File

@ -71,7 +71,7 @@ public class InvocableHandlerMethodTests {
List<HandlerResult> values = Stream.from(publisher).toList().get(); List<HandlerResult> values = Stream.from(publisher).toList().get();
assertEquals(1, values.size()); assertEquals(1, values.size());
assertEquals("success", values.get(0).getResult()); assertEquals("success", values.get(0).getReturnValue().get());
} }
@Test @Test
@ -84,7 +84,7 @@ public class InvocableHandlerMethodTests {
List<HandlerResult> values = Stream.from(publisher).toList().get(); List<HandlerResult> values = Stream.from(publisher).toList().get();
assertEquals(1, values.size()); assertEquals(1, values.size());
assertEquals("success:null", values.get(0).getResult()); assertEquals("success:null", values.get(0).getReturnValue().get());
} }
@Test @Test
@ -96,7 +96,7 @@ public class InvocableHandlerMethodTests {
List<HandlerResult> values = Stream.from(publisher).toList().get(); List<HandlerResult> values = Stream.from(publisher).toList().get();
assertEquals(1, values.size()); assertEquals(1, values.size());
assertEquals("success:value1", values.get(0).getResult()); assertEquals("success:value1", values.get(0).getReturnValue().get());
} }
@Test @Test
@ -108,7 +108,7 @@ public class InvocableHandlerMethodTests {
List<HandlerResult> values = Stream.from(publisher).toList().get(); List<HandlerResult> values = Stream.from(publisher).toList().get();
assertEquals(1, values.size()); assertEquals(1, values.size());
assertEquals("success:value1", values.get(0).getResult()); assertEquals("success:value1", values.get(0).getReturnValue().get());
} }
@Test @Test