From 5ae9afd5a55715d37a185223736725915e330b27 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Mon, 13 Mar 2017 14:02:13 -0400 Subject: [PATCH] Refactor SyncInvocableHandlerMethod Switch from extension to delegation model, i.e. delegating to InvocableHandlerMethod, so that only sync invocation is exposed and only resolvers of type SyncHandlerMethodArgumentResolver are allowed to be configured in a cleaner fashion. --- .../result/method/InvocableHandlerMethod.java | 7 +- .../method/SyncInvocableHandlerMethod.java | 64 ++++++++++++------- .../RequestMappingHandlerAdapter.java | 2 +- 3 files changed, 45 insertions(+), 28 deletions(-) diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/InvocableHandlerMethod.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/InvocableHandlerMethod.java index 3052c5160c..b7a6811f9d 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/InvocableHandlerMethod.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/InvocableHandlerMethod.java @@ -43,8 +43,9 @@ import org.springframework.web.reactive.HandlerResult; import org.springframework.web.server.ServerWebExchange; /** - * A subclass of {@link HandlerMethod} that can resolve method arguments from - * a {@link ServerWebExchange} and use that to invoke the underlying method. + * Extension of {@link HandlerMethod} that invokes the underlying method with + * argument values resolved from the current HTTP request through a list of + * {@link HandlerMethodArgumentResolver}. * * @author Rossen Stoyanchev * @author Juergen Hoeller @@ -94,7 +95,7 @@ public class InvocableHandlerMethod extends HandlerMethod { } /** - * Return the conifgured argument resolvers. + * Return the configured argument resolvers. */ public List getResolvers() { return this.resolvers; diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/SyncInvocableHandlerMethod.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/SyncInvocableHandlerMethod.java index c776cbe85c..f7365d363f 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/SyncInvocableHandlerMethod.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/SyncInvocableHandlerMethod.java @@ -19,69 +19,85 @@ package org.springframework.web.reactive.result.method; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; -import org.springframework.util.Assert; +import org.springframework.core.DefaultParameterNameDiscoverer; +import org.springframework.core.ParameterNameDiscoverer; import org.springframework.web.method.HandlerMethod; import org.springframework.web.reactive.BindingContext; import org.springframework.web.reactive.HandlerResult; import org.springframework.web.server.ServerWebExchange; /** - * Extension of {@code InvocableHandlerMethod} that can only be configured with - * synchronous argument resolvers and thus exposing an additional, synchronous - * {@link #invokeForHandlerResult} returning a {@code HandlerResult} vs - * {@code Mono}. + * Extension of {@link HandlerMethod} that invokes the underlying method via + * {@link InvocableHandlerMethod} but uses sync argument resolvers only and + * thus can return directly a {@link HandlerResult} with no async wrappers. * * @author Rossen Stoyanchev * @since 5.0 */ -public class SyncInvocableHandlerMethod extends InvocableHandlerMethod { +public class SyncInvocableHandlerMethod extends HandlerMethod { + + private final InvocableHandlerMethod delegate; public SyncInvocableHandlerMethod(HandlerMethod handlerMethod) { super(handlerMethod); + this.delegate = new InvocableHandlerMethod(handlerMethod); } public SyncInvocableHandlerMethod(Object bean, Method method) { super(bean, method); + this.delegate = new InvocableHandlerMethod(bean, method); } /** - * {@inheritDoc} - *

Resolvers must be of type {@link SyncHandlerMethodArgumentResolver}. - * @see #setSyncArgumentResolvers(List) + * Configure the argument resolvers to use to use for resolving method + * argument values against a {@code ServerWebExchange}. */ - @Override - public void setArgumentResolvers(List resolvers) { - resolvers.forEach(this::assertSyncResolvers); - super.setArgumentResolvers(resolvers); + public void setArgumentResolvers(List resolvers) { + this.delegate.setArgumentResolvers(new ArrayList<>(resolvers)); } - private void assertSyncResolvers(HandlerMethodArgumentResolver resolver) { - Assert.isInstanceOf(SyncHandlerMethodArgumentResolver.class, resolver, - "SyncInvocableHandlerMethod requires resolvers of type " + - "SyncHandlerMethodArgumentResolver"); + /** + * Return the configured argument resolvers. + */ + public List getResolvers() { + return this.delegate.getResolvers().stream() + .map(resolver -> (SyncHandlerMethodArgumentResolver) resolver) + .collect(Collectors.toList()); + } + + /** + * Set the ParameterNameDiscoverer for resolving parameter names when needed + * (e.g. default request attribute name). + *

Default is a {@link DefaultParameterNameDiscoverer}. + */ + public void setParameterNameDiscoverer(ParameterNameDiscoverer nameDiscoverer) { + this.delegate.setParameterNameDiscoverer(nameDiscoverer); } /** - * Convenient alternative to {@link #setArgumentResolvers(List)} to configure - * synchronous argument resolvers. + * Return the configured parameter name discoverer. */ - public void setSyncArgumentResolvers(List resolvers) { - setArgumentResolvers(new ArrayList<>(resolvers)); + public ParameterNameDiscoverer getParameterNameDiscoverer() { + return this.delegate.getParameterNameDiscoverer(); } /** - * Delegate to the base class {@link #invoke} and also wait for the result. - * Since all argument resolvers are synchronous this won't actually block. + * 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 match by type + * @return Mono with a {@link HandlerResult}. */ public HandlerResult invokeForHandlerResult(ServerWebExchange exchange, BindingContext bindingContext, Object... providedArgs) { // This will not block with only sync resolvers allowed - return super.invoke(exchange, bindingContext, providedArgs).block(); + return this.delegate.invoke(exchange, bindingContext, providedArgs).block(); } } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerAdapter.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerAdapter.java index 9541f91032..8df4a84c2e 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerAdapter.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerAdapter.java @@ -409,7 +409,7 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Application private SyncInvocableHandlerMethod createBinderMethod(Object bean, Method method) { SyncInvocableHandlerMethod invocable = new SyncInvocableHandlerMethod(bean, method); - invocable.setSyncArgumentResolvers(getInitBinderArgumentResolvers()); + invocable.setArgumentResolvers(getInitBinderArgumentResolvers()); return invocable; }