4242import org .springframework .http .codec .HttpMessageReader ;
4343import org .springframework .util .ReflectionUtils ;
4444import org .springframework .web .bind .annotation .InitBinder ;
45+ import org .springframework .web .bind .annotation .ModelAttribute ;
46+ import org .springframework .web .bind .annotation .RequestMapping ;
4547import org .springframework .web .bind .support .WebBindingInitializer ;
4648import org .springframework .web .method .HandlerMethod ;
4749import org .springframework .web .method .annotation .ExceptionHandlerMethodResolver ;
5153import org .springframework .web .reactive .result .method .HandlerMethodArgumentResolver ;
5254import org .springframework .web .reactive .result .method .InvocableHandlerMethod ;
5355import org .springframework .web .reactive .result .method .SyncHandlerMethodArgumentResolver ;
54- import org .springframework .web .reactive .result .method .SyncInvocableHandlerMethod ;
5556import org .springframework .web .server .ServerWebExchange ;
5657
5758/**
@@ -82,8 +83,12 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, BeanFactory
8283 private ConfigurableBeanFactory beanFactory ;
8384
8485
86+ private final BindingContextFactory bindingContextFactory = new BindingContextFactory (this );
87+
8588 private final Map <Class <?>, Set <Method >> initBinderCache = new ConcurrentHashMap <>(64 );
8689
90+ private final Map <Class <?>, Set <Method >> modelAttributeCache = new ConcurrentHashMap <>(64 );
91+
8792 private final Map <Class <?>, ExceptionHandlerMethodResolver > exceptionHandlerCache =
8893 new ConcurrentHashMap <>(64 );
8994
@@ -225,11 +230,12 @@ protected List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
225230 List <HandlerMethodArgumentResolver > resolvers = new ArrayList <>();
226231
227232 // Annotation-based argument resolution
228- resolvers .add (new RequestParamMethodArgumentResolver (getBeanFactory (), false ));
233+ resolvers .add (new RequestParamMethodArgumentResolver (getBeanFactory ()));
229234 resolvers .add (new RequestParamMapMethodArgumentResolver ());
230235 resolvers .add (new PathVariableMethodArgumentResolver (getBeanFactory ()));
231236 resolvers .add (new PathVariableMapMethodArgumentResolver ());
232237 resolvers .add (new RequestBodyArgumentResolver (getMessageReaders (), getReactiveAdapterRegistry ()));
238+ resolvers .add (new ModelAttributeMethodArgumentResolver (getReactiveAdapterRegistry ()));
233239 resolvers .add (new RequestHeaderMethodArgumentResolver (getBeanFactory ()));
234240 resolvers .add (new RequestHeaderMapMethodArgumentResolver ());
235241 resolvers .add (new CookieValueMethodArgumentResolver (getBeanFactory ()));
@@ -240,6 +246,7 @@ protected List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
240246 // Type-based argument resolution
241247 resolvers .add (new HttpEntityArgumentResolver (getMessageReaders (), getReactiveAdapterRegistry ()));
242248 resolvers .add (new ModelArgumentResolver ());
249+ resolvers .add (new ErrorsMethodArgumentResolver (getReactiveAdapterRegistry ()));
243250 resolvers .add (new ServerWebExchangeArgumentResolver ());
244251 resolvers .add (new PrincipalArgumentResolver ());
245252 resolvers .add (new WebSessionArgumentResolver ());
@@ -251,6 +258,7 @@ protected List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
251258
252259 // Catch-all
253260 resolvers .add (new RequestParamMethodArgumentResolver (getBeanFactory (), true ));
261+ resolvers .add (new ModelAttributeMethodArgumentResolver (getReactiveAdapterRegistry (), true ));
254262 return resolvers ;
255263 }
256264
@@ -290,34 +298,31 @@ public boolean supports(Object handler) {
290298
291299 @ Override
292300 public Mono <HandlerResult > handle (ServerWebExchange exchange , Object handler ) {
301+
293302 HandlerMethod handlerMethod = (HandlerMethod ) handler ;
294303 InvocableHandlerMethod invocable = new InvocableHandlerMethod (handlerMethod );
295304 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 )));
302315 }
303316
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 ));
319320 }
320321
322+ Set <Method > getModelAttributeMethods (Class <?> handlerType ) {
323+ return this .modelAttributeCache .computeIfAbsent (handlerType , aClass ->
324+ MethodIntrospector .selectMethods (handlerType , MODEL_ATTRIBUTE_METHODS ));
325+ }
321326
322327 private Mono <HandlerResult > handleException (Throwable ex , HandlerMethod handlerMethod ,
323328 BindingContext bindingContext , ServerWebExchange exchange ) {
@@ -360,7 +365,14 @@ protected InvocableHandlerMethod findExceptionHandler(HandlerMethod handlerMetho
360365 /**
361366 * MethodFilter that matches {@link InitBinder @InitBinder} methods.
362367 */
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 );
365377
366378}
0 commit comments