2121import java .util .ArrayList ;
2222import java .util .Arrays ;
2323import java .util .List ;
24+ import java .util .Optional ;
2425import java .util .stream .Collectors ;
2526import java .util .stream .IntStream ;
2627import java .util .stream .Stream ;
4041import org .springframework .web .server .ServerWebExchange ;
4142
4243/**
43- * Extension of HandlerMethod that can invoke the target method after resolving
44- * its method arguments .
44+ * A sub-class of {@link HandlerMethod} that can resolve method arguments from
45+ * a {@link ServerWebExchange} and use that to invoke the underlying method .
4546 *
4647 * @author Rossen Stoyanchev
4748 * @since 5.0
4849 */
4950public class InvocableHandlerMethod extends HandlerMethod {
5051
51- private static final Mono <Object []> NO_ARGS = Mono .just (new Object [0 ]);
52+ private static final Mono <Object []> EMPTY_ARGS = Mono .just (new Object [0 ]);
5253
53- private static final Object NO_VALUE = new Object ();
54+ private static final Object NO_ARG_VALUE = new Object ();
5455
5556
5657 private List <HandlerMethodArgumentResolver > resolvers = new ArrayList <>();
@@ -68,8 +69,8 @@ public InvocableHandlerMethod(Object bean, Method method) {
6869
6970
7071 /**
71- * Set {@link HandlerMethodArgumentResolver}s to use to use for resolving
72- * method argument values.
72+ * Configure the argument resolvers to use to use for resolving method
73+ * argument values against a {@code ServerWebExchange} .
7374 */
7475 public void setArgumentResolvers (List <HandlerMethodArgumentResolver > resolvers ) {
7576 this .resolvers .clear ();
@@ -81,24 +82,18 @@ public void setArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers)
8182 * (e.g. default request attribute name).
8283 * <p>Default is a {@link DefaultParameterNameDiscoverer}.
8384 */
84- public void setParameterNameDiscoverer (ParameterNameDiscoverer parameterNameDiscoverer ) {
85- this .parameterNameDiscoverer = parameterNameDiscoverer ;
86- }
87-
88- @ Override
89- protected Method getBridgedMethod () {
90- return super .getBridgedMethod ();
85+ public void setParameterNameDiscoverer (ParameterNameDiscoverer nameDiscoverer ) {
86+ this .parameterNameDiscoverer = nameDiscoverer ;
9187 }
9288
9389
9490 /**
95- * Invoke the method and return a Publisher for the return value.
91+ * Invoke the method for the given exchange.
92+ *
9693 * @param exchange the current exchange
9794 * @param bindingContext the binding context to use
98- * @param providedArgs optional list of argument values to check by type
99- * (via {@code instanceof}) for resolving method arguments.
100- * @return Publisher that produces a single HandlerResult or an error signal;
101- * never throws an exception
95+ * @param providedArgs optional list of argument values to match by type
96+ * @return Mono with a {@link HandlerResult}.
10297 */
10398 public Mono <HandlerResult > invoke (ServerWebExchange exchange ,
10499 BindingContext bindingContext , Object ... providedArgs ) {
@@ -124,59 +119,73 @@ private Mono<Object[]> resolveArguments(ServerWebExchange exchange,
124119 BindingContext bindingContext , Object ... providedArgs ) {
125120
126121 if (ObjectUtils .isEmpty (getMethodParameters ())) {
127- return NO_ARGS ;
122+ return EMPTY_ARGS ;
128123 }
129124 try {
130- List <Mono <Object >> monos = Stream .of (getMethodParameters ())
125+ List <Mono <Object >> argMonos = Stream .of (getMethodParameters ())
131126 .map (param -> {
132127 param .initParameterNameDiscovery (this .parameterNameDiscoverer );
133128 GenericTypeResolver .resolveParameterType (param , getBean ().getClass ());
134- if (!ObjectUtils .isEmpty (providedArgs )) {
135- for (Object providedArg : providedArgs ) {
136- if (param .getParameterType ().isInstance (providedArg )) {
137- return Mono .just (providedArg ).log ("reactor.resolved" );
138- }
139- }
140- }
141- HandlerMethodArgumentResolver resolver = this .resolvers .stream ()
142- .filter (r -> r .supportsParameter (param ))
143- .findFirst ()
144- .orElseThrow (() -> getArgError ("No resolver for " , param , null ));
145- try {
146- return resolver .resolveArgument (param , bindingContext , exchange )
147- .defaultIfEmpty (NO_VALUE )
148- .doOnError (cause -> {
149- if (logger .isDebugEnabled ()) {
150- logger .debug (getDetailedErrorMessage ("Error resolving " , param ), cause );
151- }
152- })
153- .log ("reactor.unresolved" );
154- }
155- catch (Exception ex ) {
156- throw getArgError ("Error resolving " , param , ex );
157- }
129+ return findProvidedArg (param , providedArgs )
130+ .map (Mono ::just )
131+ .orElseGet (() -> {
132+ HandlerMethodArgumentResolver resolver = findResolver (param );
133+ return resolveArg (resolver , param , bindingContext , exchange );
134+ });
135+
158136 })
159137 .collect (Collectors .toList ());
160138
161139 // Create Mono with array of resolved values...
162- return Mono .when (monos ,
163- args -> Stream .of (args ).map (o -> o != NO_VALUE ? o : null ).toArray ());
140+ return Mono .when (argMonos , argValues ->
141+ Stream .of (argValues ).map (o -> o != NO_ARG_VALUE ? o : null ).toArray ());
164142 }
165143 catch (Throwable ex ) {
166144 return Mono .error (ex );
167145 }
168146 }
169147
170- private IllegalStateException getArgError (String message , MethodParameter param , Throwable cause ) {
171- return new IllegalStateException (getDetailedErrorMessage (message , param ), cause );
148+ private Optional <Object > findProvidedArg (MethodParameter param , Object ... providedArgs ) {
149+ if (ObjectUtils .isEmpty (providedArgs )) {
150+ return Optional .empty ();
151+ }
152+ return Arrays .stream (providedArgs )
153+ .filter (arg -> param .getParameterType ().isInstance (arg ))
154+ .findFirst ();
155+ }
156+
157+ private HandlerMethodArgumentResolver findResolver (MethodParameter param ) {
158+ return this .resolvers .stream ()
159+ .filter (r -> r .supportsParameter (param ))
160+ .findFirst ()
161+ .orElseThrow (() -> getArgumentError ("No resolver for " , param , null ));
162+ }
163+
164+ private Mono <Object > resolveArg (HandlerMethodArgumentResolver resolver , MethodParameter param ,
165+ BindingContext bindingContext , ServerWebExchange exchange ) {
166+
167+ try {
168+ return resolver .resolveArgument (param , bindingContext , exchange )
169+ .defaultIfEmpty (NO_ARG_VALUE )
170+ .doOnError (cause -> {
171+ if (logger .isDebugEnabled ()) {
172+ logger .debug (getDetailedErrorMessage ("Error resolving " , param ), cause );
173+ }
174+ });
175+ }
176+ catch (Exception ex ) {
177+ throw getArgumentError ("Error resolving " , param , ex );
178+ }
179+ }
180+
181+ private IllegalStateException getArgumentError (String message , MethodParameter param , Throwable ex ) {
182+ return new IllegalStateException (getDetailedErrorMessage (message , param ), ex );
172183 }
173184
174185 private String getDetailedErrorMessage (String message , MethodParameter param ) {
175- StringBuilder sb = new StringBuilder (message );
176- sb .append ("argument [" ).append (param .getParameterIndex ()).append ("] " );
177- sb .append ("of type [" ).append (param .getParameterType ().getName ()).append ("] " );
178- sb .append ("on method [" ).append (getBridgedMethod ().toGenericString ()).append ("]" );
179- return sb .toString ();
186+ return message + "argument [" + param .getParameterIndex () + "] " +
187+ "of type [" + param .getParameterType ().getName () + "] " +
188+ "on method [" + getBridgedMethod ().toGenericString () + "]" ;
180189 }
181190
182191 private Object doInvoke (Object [] args ) throws Exception {
0 commit comments