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;
}
}
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;
import java.util.Optional;
import java.util.function.Function;
import reactor.core.publisher.Mono;
@ -32,40 +33,54 @@ public class HandlerResult {
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;
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, "'resultType' is required");
Assert.notNull(returnValueType, "'returnValueType' is required");
this.handler = handler;
this.result = result;
this.resultType = resultType;
this.returnValue = Optional.ofNullable(returnValue);
this.returnValueType = returnValueType;
}
/**
* Return the handler that handled the request.
*/
public Object getHandler() {
return this.handler;
}
public Object getResult() {
return this.result;
}
public ResolvableType getResultType() {
return this.resultType;
/**
* Return the value returned from the handler wrapped as {@link Optional}.
*/
public Optional<Object> getReturnValue() {
return this.returnValue;
}
/**
* For an async result, failures may occur later during result handling.
* Use this property to configure an exception handler to be invoked if
* result handling fails.
*
* @param function a function to map the the error to an alternative result.
* Return the type of the value returned from the handler.
*/
public ResolvableType getReturnValueType() {
return this.returnValueType;
}
/**
* 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
*/
public HandlerResult setExceptionHandler(Function<Throwable, Mono<HandlerResult>> function) {
@ -73,12 +88,20 @@ public class HandlerResult {
return this;
}
/**
* Whether there is an exception handler.
*/
public boolean hasExceptionHandler() {
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;
import java.util.Optional;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Mono;
@ -61,7 +63,7 @@ public class SimpleHandlerResultHandler implements Ordered, HandlerResultHandler
@Override
public boolean supports(HandlerResult result) {
ResolvableType type = result.getResultType();
ResolvableType type = result.getReturnValueType();
return (type != null && Void.TYPE.equals(type.getRawClass()) ||
(isConvertibleToPublisher(type) && Void.class.isAssignableFrom(type.getGeneric(0).getRawClass())));
}
@ -75,12 +77,14 @@ public class SimpleHandlerResultHandler implements Ordered, HandlerResultHandler
@SuppressWarnings("unchecked")
@Override
public Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {
Object value = result.getResult();
if (Void.TYPE.equals(result.getResultType().getRawClass())) {
Optional<Object> value = result.getReturnValue();
if (!value.isPresent() || Void.TYPE.equals(result.getReturnValueType().getRawClass())) {
return Mono.empty();
}
return (value instanceof Mono ? (Mono<Void>)value :
Mono.from(this.conversionService.convert(value, Publisher.class)));
if (value.get() instanceof Mono) {
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.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
@ -132,23 +133,23 @@ public class ResponseBodyResultHandler implements HandlerResultHandler, Ordered
@SuppressWarnings("unchecked")
public Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {
Object value = result.getResult();
if (value == null) {
Optional<Object> value = result.getReturnValue();
if (!value.isPresent()) {
return Mono.empty();
}
Publisher<?> publisher;
ResolvableType elementType;
ResolvableType returnType = result.getResultType();
ResolvableType returnType = result.getReturnValueType();
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);
if (Void.class.equals(elementType.getRawClass())) {
return (Mono<Void>)Mono.from(publisher);
}
}
else {
publisher = Mono.just(value);
publisher = Mono.just(value.get());
elementType = returnType;
}

View File

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