42
42
import org .springframework .http .codec .HttpMessageReader ;
43
43
import org .springframework .util .ReflectionUtils ;
44
44
import org .springframework .web .bind .annotation .InitBinder ;
45
+ import org .springframework .web .bind .annotation .ModelAttribute ;
46
+ import org .springframework .web .bind .annotation .RequestMapping ;
45
47
import org .springframework .web .bind .support .WebBindingInitializer ;
46
48
import org .springframework .web .method .HandlerMethod ;
47
49
import org .springframework .web .method .annotation .ExceptionHandlerMethodResolver ;
51
53
import org .springframework .web .reactive .result .method .HandlerMethodArgumentResolver ;
52
54
import org .springframework .web .reactive .result .method .InvocableHandlerMethod ;
53
55
import org .springframework .web .reactive .result .method .SyncHandlerMethodArgumentResolver ;
54
- import org .springframework .web .reactive .result .method .SyncInvocableHandlerMethod ;
55
56
import org .springframework .web .server .ServerWebExchange ;
56
57
57
58
/**
@@ -82,8 +83,12 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, BeanFactory
82
83
private ConfigurableBeanFactory beanFactory ;
83
84
84
85
86
+ private final BindingContextFactory bindingContextFactory = new BindingContextFactory (this );
87
+
85
88
private final Map <Class <?>, Set <Method >> initBinderCache = new ConcurrentHashMap <>(64 );
86
89
90
+ private final Map <Class <?>, Set <Method >> modelAttributeCache = new ConcurrentHashMap <>(64 );
91
+
87
92
private final Map <Class <?>, ExceptionHandlerMethodResolver > exceptionHandlerCache =
88
93
new ConcurrentHashMap <>(64 );
89
94
@@ -225,11 +230,12 @@ protected List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
225
230
List <HandlerMethodArgumentResolver > resolvers = new ArrayList <>();
226
231
227
232
// Annotation-based argument resolution
228
- resolvers .add (new RequestParamMethodArgumentResolver (getBeanFactory (), false ));
233
+ resolvers .add (new RequestParamMethodArgumentResolver (getBeanFactory ()));
229
234
resolvers .add (new RequestParamMapMethodArgumentResolver ());
230
235
resolvers .add (new PathVariableMethodArgumentResolver (getBeanFactory ()));
231
236
resolvers .add (new PathVariableMapMethodArgumentResolver ());
232
237
resolvers .add (new RequestBodyArgumentResolver (getMessageReaders (), getReactiveAdapterRegistry ()));
238
+ resolvers .add (new ModelAttributeMethodArgumentResolver (getReactiveAdapterRegistry ()));
233
239
resolvers .add (new RequestHeaderMethodArgumentResolver (getBeanFactory ()));
234
240
resolvers .add (new RequestHeaderMapMethodArgumentResolver ());
235
241
resolvers .add (new CookieValueMethodArgumentResolver (getBeanFactory ()));
@@ -240,6 +246,7 @@ protected List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
240
246
// Type-based argument resolution
241
247
resolvers .add (new HttpEntityArgumentResolver (getMessageReaders (), getReactiveAdapterRegistry ()));
242
248
resolvers .add (new ModelArgumentResolver ());
249
+ resolvers .add (new ErrorsMethodArgumentResolver (getReactiveAdapterRegistry ()));
243
250
resolvers .add (new ServerWebExchangeArgumentResolver ());
244
251
resolvers .add (new PrincipalArgumentResolver ());
245
252
resolvers .add (new WebSessionArgumentResolver ());
@@ -251,6 +258,7 @@ protected List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
251
258
252
259
// Catch-all
253
260
resolvers .add (new RequestParamMethodArgumentResolver (getBeanFactory (), true ));
261
+ resolvers .add (new ModelAttributeMethodArgumentResolver (getReactiveAdapterRegistry (), true ));
254
262
return resolvers ;
255
263
}
256
264
@@ -290,34 +298,31 @@ public boolean supports(Object handler) {
290
298
291
299
@ Override
292
300
public Mono <HandlerResult > handle (ServerWebExchange exchange , Object handler ) {
301
+
293
302
HandlerMethod handlerMethod = (HandlerMethod ) handler ;
294
303
InvocableHandlerMethod invocable = new InvocableHandlerMethod (handlerMethod );
295
304
invocable .setArgumentResolvers (getArgumentResolvers ());
296
- BindingContext bindingContext = getBindingContext (handlerMethod );
297
- return invocable .invoke (exchange , bindingContext )
298
- .map (result -> result .setExceptionHandler (
299
- ex -> handleException (ex , handlerMethod , bindingContext , exchange )))
300
- .otherwise (ex -> handleException (
301
- ex , handlerMethod , bindingContext , exchange ));
305
+
306
+ Mono <BindingContext > bindingContextMono =
307
+ this .bindingContextFactory .createBindingContext (handlerMethod , exchange );
308
+
309
+ return bindingContextMono .then (bindingContext ->
310
+ invocable .invoke (exchange , bindingContext )
311
+ .doOnNext (result -> result .setExceptionHandler (
312
+ ex -> handleException (ex , handlerMethod , bindingContext , exchange )))
313
+ .otherwise (ex -> handleException (
314
+ ex , handlerMethod , bindingContext , exchange )));
302
315
}
303
316
304
- private BindingContext getBindingContext (HandlerMethod handlerMethod ) {
305
- Class <?> handlerType = handlerMethod .getBeanType ();
306
- Set <Method > methods = this .initBinderCache .get (handlerType );
307
- if (methods == null ) {
308
- methods = MethodIntrospector .selectMethods (handlerType , INIT_BINDER_METHODS );
309
- this .initBinderCache .put (handlerType , methods );
310
- }
311
- List <SyncInvocableHandlerMethod > initBinderMethods = new ArrayList <>();
312
- for (Method method : methods ) {
313
- Object bean = handlerMethod .getBean ();
314
- SyncInvocableHandlerMethod initBinderMethod = new SyncInvocableHandlerMethod (bean , method );
315
- initBinderMethod .setSyncArgumentResolvers (getInitBinderArgumentResolvers ());
316
- initBinderMethods .add (initBinderMethod );
317
- }
318
- return new InitBinderBindingContext (getWebBindingInitializer (), initBinderMethods );
317
+ Set <Method > getInitBinderMethods (Class <?> handlerType ) {
318
+ return this .initBinderCache .computeIfAbsent (handlerType , aClass ->
319
+ MethodIntrospector .selectMethods (handlerType , INIT_BINDER_METHODS ));
319
320
}
320
321
322
+ Set <Method > getModelAttributeMethods (Class <?> handlerType ) {
323
+ return this .modelAttributeCache .computeIfAbsent (handlerType , aClass ->
324
+ MethodIntrospector .selectMethods (handlerType , MODEL_ATTRIBUTE_METHODS ));
325
+ }
321
326
322
327
private Mono <HandlerResult > handleException (Throwable ex , HandlerMethod handlerMethod ,
323
328
BindingContext bindingContext , ServerWebExchange exchange ) {
@@ -360,7 +365,14 @@ protected InvocableHandlerMethod findExceptionHandler(HandlerMethod handlerMetho
360
365
/**
361
366
* MethodFilter that matches {@link InitBinder @InitBinder} methods.
362
367
*/
363
- public static final ReflectionUtils .MethodFilter INIT_BINDER_METHODS =
364
- method -> AnnotationUtils .findAnnotation (method , InitBinder .class ) != null ;
368
+ public static final ReflectionUtils .MethodFilter INIT_BINDER_METHODS = method ->
369
+ AnnotationUtils .findAnnotation (method , InitBinder .class ) != null ;
370
+
371
+ /**
372
+ * MethodFilter that matches {@link ModelAttribute @ModelAttribute} methods.
373
+ */
374
+ public static final ReflectionUtils .MethodFilter MODEL_ATTRIBUTE_METHODS = method ->
375
+ (AnnotationUtils .findAnnotation (method , RequestMapping .class ) == null ) &&
376
+ (AnnotationUtils .findAnnotation (method , ModelAttribute .class ) != null );
365
377
366
378
}
0 commit comments