Skip to content

Commit e1a382b

Browse files
committed
Polish
1 parent b07d40c commit e1a382b

File tree

3 files changed

+80
-60
lines changed

3 files changed

+80
-60
lines changed

spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/InvocableHandlerMethod.java

Lines changed: 62 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.util.ArrayList;
2222
import java.util.Arrays;
2323
import java.util.List;
24+
import java.util.Optional;
2425
import java.util.stream.Collectors;
2526
import java.util.stream.IntStream;
2627
import java.util.stream.Stream;
@@ -40,17 +41,17 @@
4041
import 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
*/
4950
public 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 {

spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/SyncInvocableHandlerMethod.java

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
package org.springframework.web.reactive.result.method;
1717

1818
import java.lang.reflect.Method;
19-
import java.util.Collections;
19+
import java.util.ArrayList;
2020
import java.util.List;
2121

2222
import org.springframework.util.Assert;
@@ -25,9 +25,10 @@
2525
import org.springframework.web.server.ServerWebExchange;
2626

2727
/**
28-
* An extension of {@code InvocableHandlerMethod} for use with
29-
* {@link SyncHandlerMethodArgumentResolver}s which in turn enables synchronous
30-
* handler method invocation via {@link #invokeForHandlerResult}.
28+
* An extension of {@code InvocableHandlerMethod} for synchronous, non-blocking
29+
* method invocation via {@link #invokeForHandlerResult}. By allowing only
30+
* {@link SyncHandlerMethodArgumentResolver}s to be configured, the invocation
31+
* is guaranteed to be non-blocking.
3132
*
3233
* @author Rossen Stoyanchev
3334
* @since 5.0
@@ -45,8 +46,9 @@ public SyncInvocableHandlerMethod(Object bean, Method method) {
4546

4647

4748
/**
48-
* Overloaded variant of the same setter from the base class that ensures
49-
* all resolvers are {@link SyncHandlerMethodArgumentResolver}.
49+
* {@inheritDoc}
50+
* <p>Resolvers must be of type {@link SyncHandlerMethodArgumentResolver}.
51+
* @see #setSyncArgumentResolvers(List)
5052
*/
5153
@Override
5254
public void setArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
@@ -56,6 +58,15 @@ public void setArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers)
5658
super.setArgumentResolvers(resolvers);
5759
}
5860

61+
/**
62+
* Convenient alternative to {@link #setArgumentResolvers(List)} to configure
63+
* synchronous argument resolvers.
64+
*/
65+
public void setSyncArgumentResolvers(List<SyncHandlerMethodArgumentResolver> resolvers) {
66+
setArgumentResolvers(new ArrayList<>(resolvers));
67+
}
68+
69+
5970
/**
6071
* Delegate to the base class {@link #invoke} and also wait for the result.
6172
* Since all argument resolvers are synchronous this won't actually block.

spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerAdapter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ private BindingContext getBindingContext(HandlerMethod handlerMethod) {
311311
for (Method method : methods) {
312312
Object bean = handlerMethod.getBean();
313313
SyncInvocableHandlerMethod initBinderMethod = new SyncInvocableHandlerMethod(bean, method);
314-
initBinderMethod.setArgumentResolvers(new ArrayList<>(this.initBinderArgumentResolvers));
314+
initBinderMethod.setSyncArgumentResolvers(getInitBinderArgumentResolvers());
315315
initBinderMethods.add(initBinderMethod);
316316
}
317317
return new InitBinderBindingContext(getWebBindingInitializer(), initBinderMethods);

0 commit comments

Comments
 (0)