Polish
This commit is contained in:
parent
b07d40cc44
commit
e1a382b61f
|
|
@ -21,6 +21,7 @@ import java.lang.reflect.Method;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
|
|
@ -40,17 +41,17 @@ import org.springframework.web.reactive.HandlerResult;
|
|||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
/**
|
||||
* Extension of HandlerMethod that can invoke the target method after resolving
|
||||
* its method arguments.
|
||||
* A sub-class of {@link HandlerMethod} that can resolve method arguments from
|
||||
* a {@link ServerWebExchange} and use that to invoke the underlying method.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 5.0
|
||||
*/
|
||||
public class InvocableHandlerMethod extends HandlerMethod {
|
||||
|
||||
private static final Mono<Object[]> NO_ARGS = Mono.just(new Object[0]);
|
||||
private static final Mono<Object[]> EMPTY_ARGS = Mono.just(new Object[0]);
|
||||
|
||||
private static final Object NO_VALUE = new Object();
|
||||
private static final Object NO_ARG_VALUE = new Object();
|
||||
|
||||
|
||||
private List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();
|
||||
|
|
@ -68,8 +69,8 @@ public class InvocableHandlerMethod extends HandlerMethod {
|
|||
|
||||
|
||||
/**
|
||||
* Set {@link HandlerMethodArgumentResolver}s to use to use for resolving
|
||||
* method argument values.
|
||||
* Configure the argument resolvers to use to use for resolving method
|
||||
* argument values against a {@code ServerWebExchange}.
|
||||
*/
|
||||
public void setArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
|
||||
this.resolvers.clear();
|
||||
|
|
@ -81,24 +82,18 @@ public class InvocableHandlerMethod extends HandlerMethod {
|
|||
* (e.g. default request attribute name).
|
||||
* <p>Default is a {@link DefaultParameterNameDiscoverer}.
|
||||
*/
|
||||
public void setParameterNameDiscoverer(ParameterNameDiscoverer parameterNameDiscoverer) {
|
||||
this.parameterNameDiscoverer = parameterNameDiscoverer;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Method getBridgedMethod() {
|
||||
return super.getBridgedMethod();
|
||||
public void setParameterNameDiscoverer(ParameterNameDiscoverer nameDiscoverer) {
|
||||
this.parameterNameDiscoverer = nameDiscoverer;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Invoke the method and return a Publisher for the return value.
|
||||
* Invoke the method for the given exchange.
|
||||
*
|
||||
* @param exchange the current exchange
|
||||
* @param bindingContext the binding context to use
|
||||
* @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
|
||||
* @param providedArgs optional list of argument values to match by type
|
||||
* @return Mono with a {@link HandlerResult}.
|
||||
*/
|
||||
public Mono<HandlerResult> invoke(ServerWebExchange exchange,
|
||||
BindingContext bindingContext, Object... providedArgs) {
|
||||
|
|
@ -124,59 +119,73 @@ public class InvocableHandlerMethod extends HandlerMethod {
|
|||
BindingContext bindingContext, Object... providedArgs) {
|
||||
|
||||
if (ObjectUtils.isEmpty(getMethodParameters())) {
|
||||
return NO_ARGS;
|
||||
return EMPTY_ARGS;
|
||||
}
|
||||
try {
|
||||
List<Mono<Object>> monos = Stream.of(getMethodParameters())
|
||||
List<Mono<Object>> argMonos = Stream.of(getMethodParameters())
|
||||
.map(param -> {
|
||||
param.initParameterNameDiscovery(this.parameterNameDiscoverer);
|
||||
GenericTypeResolver.resolveParameterType(param, getBean().getClass());
|
||||
if (!ObjectUtils.isEmpty(providedArgs)) {
|
||||
for (Object providedArg : providedArgs) {
|
||||
if (param.getParameterType().isInstance(providedArg)) {
|
||||
return Mono.just(providedArg).log("reactor.resolved");
|
||||
}
|
||||
}
|
||||
}
|
||||
HandlerMethodArgumentResolver resolver = this.resolvers.stream()
|
||||
.filter(r -> r.supportsParameter(param))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> getArgError("No resolver for ", param, null));
|
||||
try {
|
||||
return resolver.resolveArgument(param, bindingContext, exchange)
|
||||
.defaultIfEmpty(NO_VALUE)
|
||||
.doOnError(cause -> {
|
||||
if(logger.isDebugEnabled()) {
|
||||
logger.debug(getDetailedErrorMessage("Error resolving ", param), cause);
|
||||
}
|
||||
})
|
||||
.log("reactor.unresolved");
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw getArgError("Error resolving ", param, ex);
|
||||
}
|
||||
return findProvidedArg(param, providedArgs)
|
||||
.map(Mono::just)
|
||||
.orElseGet(() -> {
|
||||
HandlerMethodArgumentResolver resolver = findResolver(param);
|
||||
return resolveArg(resolver, param, bindingContext, exchange);
|
||||
});
|
||||
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// Create Mono with array of resolved values...
|
||||
return Mono.when(monos,
|
||||
args -> Stream.of(args).map(o -> o != NO_VALUE ? o : null).toArray());
|
||||
return Mono.when(argMonos, argValues ->
|
||||
Stream.of(argValues).map(o -> o != NO_ARG_VALUE ? o : null).toArray());
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
return Mono.error(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private IllegalStateException getArgError(String message, MethodParameter param, Throwable cause) {
|
||||
return new IllegalStateException(getDetailedErrorMessage(message, param), cause);
|
||||
private Optional<Object> findProvidedArg(MethodParameter param, Object... providedArgs) {
|
||||
if (ObjectUtils.isEmpty(providedArgs)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return Arrays.stream(providedArgs)
|
||||
.filter(arg -> param.getParameterType().isInstance(arg))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
private HandlerMethodArgumentResolver findResolver(MethodParameter param) {
|
||||
return this.resolvers.stream()
|
||||
.filter(r -> r.supportsParameter(param))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> getArgumentError("No resolver for ", param, null));
|
||||
}
|
||||
|
||||
private Mono<Object> resolveArg(HandlerMethodArgumentResolver resolver, MethodParameter param,
|
||||
BindingContext bindingContext, ServerWebExchange exchange) {
|
||||
|
||||
try {
|
||||
return resolver.resolveArgument(param, bindingContext, exchange)
|
||||
.defaultIfEmpty(NO_ARG_VALUE)
|
||||
.doOnError(cause -> {
|
||||
if(logger.isDebugEnabled()) {
|
||||
logger.debug(getDetailedErrorMessage("Error resolving ", param), cause);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw getArgumentError("Error resolving ", param, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private IllegalStateException getArgumentError(String message, MethodParameter param, Throwable ex) {
|
||||
return new IllegalStateException(getDetailedErrorMessage(message, param), ex);
|
||||
}
|
||||
|
||||
private String getDetailedErrorMessage(String message, MethodParameter param) {
|
||||
StringBuilder sb = new StringBuilder(message);
|
||||
sb.append("argument [").append(param.getParameterIndex()).append("] ");
|
||||
sb.append("of type [").append(param.getParameterType().getName()).append("] ");
|
||||
sb.append("on method [").append(getBridgedMethod().toGenericString()).append("]");
|
||||
return sb.toString();
|
||||
return message + "argument [" + param.getParameterIndex() + "] " +
|
||||
"of type [" + param.getParameterType().getName() + "] " +
|
||||
"on method [" + getBridgedMethod().toGenericString() + "]";
|
||||
}
|
||||
|
||||
private Object doInvoke(Object[] args) throws Exception {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
package org.springframework.web.reactive.result.method;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
|
@ -25,9 +25,10 @@ import org.springframework.web.reactive.HandlerResult;
|
|||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
/**
|
||||
* An extension of {@code InvocableHandlerMethod} for use with
|
||||
* {@link SyncHandlerMethodArgumentResolver}s which in turn enables synchronous
|
||||
* handler method invocation via {@link #invokeForHandlerResult}.
|
||||
* An extension of {@code InvocableHandlerMethod} for synchronous, non-blocking
|
||||
* method invocation via {@link #invokeForHandlerResult}. By allowing only
|
||||
* {@link SyncHandlerMethodArgumentResolver}s to be configured, the invocation
|
||||
* is guaranteed to be non-blocking.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 5.0
|
||||
|
|
@ -45,8 +46,9 @@ public class SyncInvocableHandlerMethod extends InvocableHandlerMethod {
|
|||
|
||||
|
||||
/**
|
||||
* Overloaded variant of the same setter from the base class that ensures
|
||||
* all resolvers are {@link SyncHandlerMethodArgumentResolver}.
|
||||
* {@inheritDoc}
|
||||
* <p>Resolvers must be of type {@link SyncHandlerMethodArgumentResolver}.
|
||||
* @see #setSyncArgumentResolvers(List)
|
||||
*/
|
||||
@Override
|
||||
public void setArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
|
||||
|
|
@ -56,6 +58,15 @@ public class SyncInvocableHandlerMethod extends InvocableHandlerMethod {
|
|||
super.setArgumentResolvers(resolvers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenient alternative to {@link #setArgumentResolvers(List)} to configure
|
||||
* synchronous argument resolvers.
|
||||
*/
|
||||
public void setSyncArgumentResolvers(List<SyncHandlerMethodArgumentResolver> resolvers) {
|
||||
setArgumentResolvers(new ArrayList<>(resolvers));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Delegate to the base class {@link #invoke} and also wait for the result.
|
||||
* Since all argument resolvers are synchronous this won't actually block.
|
||||
|
|
|
|||
|
|
@ -311,7 +311,7 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, BeanFactory
|
|||
for (Method method : methods) {
|
||||
Object bean = handlerMethod.getBean();
|
||||
SyncInvocableHandlerMethod initBinderMethod = new SyncInvocableHandlerMethod(bean, method);
|
||||
initBinderMethod.setArgumentResolvers(new ArrayList<>(this.initBinderArgumentResolvers));
|
||||
initBinderMethod.setSyncArgumentResolvers(getInitBinderArgumentResolvers());
|
||||
initBinderMethods.add(initBinderMethod);
|
||||
}
|
||||
return new InitBinderBindingContext(getWebBindingInitializer(), initBinderMethods);
|
||||
|
|
|
|||
Loading…
Reference in New Issue