001/*
002 * Copyright 2002-2020 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.web.servlet.mvc.method.annotation;
018
019import java.lang.reflect.Method;
020import java.util.ArrayList;
021import java.util.LinkedHashMap;
022import java.util.List;
023import java.util.Map;
024import java.util.Set;
025import java.util.concurrent.Callable;
026import java.util.concurrent.ConcurrentHashMap;
027
028import javax.servlet.http.HttpServletRequest;
029import javax.servlet.http.HttpServletResponse;
030import javax.servlet.http.HttpSession;
031
032import org.springframework.beans.factory.BeanFactory;
033import org.springframework.beans.factory.BeanFactoryAware;
034import org.springframework.beans.factory.InitializingBean;
035import org.springframework.beans.factory.config.ConfigurableBeanFactory;
036import org.springframework.core.DefaultParameterNameDiscoverer;
037import org.springframework.core.MethodIntrospector;
038import org.springframework.core.ParameterNameDiscoverer;
039import org.springframework.core.ReactiveAdapterRegistry;
040import org.springframework.core.annotation.AnnotatedElementUtils;
041import org.springframework.core.log.LogFormatUtils;
042import org.springframework.core.task.AsyncTaskExecutor;
043import org.springframework.core.task.SimpleAsyncTaskExecutor;
044import org.springframework.http.converter.ByteArrayHttpMessageConverter;
045import org.springframework.http.converter.HttpMessageConverter;
046import org.springframework.http.converter.StringHttpMessageConverter;
047import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;
048import org.springframework.http.converter.xml.SourceHttpMessageConverter;
049import org.springframework.lang.Nullable;
050import org.springframework.ui.ModelMap;
051import org.springframework.util.CollectionUtils;
052import org.springframework.util.ReflectionUtils.MethodFilter;
053import org.springframework.web.accept.ContentNegotiationManager;
054import org.springframework.web.bind.annotation.InitBinder;
055import org.springframework.web.bind.annotation.ModelAttribute;
056import org.springframework.web.bind.annotation.RequestMapping;
057import org.springframework.web.bind.support.DefaultDataBinderFactory;
058import org.springframework.web.bind.support.DefaultSessionAttributeStore;
059import org.springframework.web.bind.support.SessionAttributeStore;
060import org.springframework.web.bind.support.WebBindingInitializer;
061import org.springframework.web.bind.support.WebDataBinderFactory;
062import org.springframework.web.context.request.NativeWebRequest;
063import org.springframework.web.context.request.ServletWebRequest;
064import org.springframework.web.context.request.WebRequest;
065import org.springframework.web.context.request.async.AsyncWebRequest;
066import org.springframework.web.context.request.async.CallableProcessingInterceptor;
067import org.springframework.web.context.request.async.DeferredResultProcessingInterceptor;
068import org.springframework.web.context.request.async.WebAsyncManager;
069import org.springframework.web.context.request.async.WebAsyncTask;
070import org.springframework.web.context.request.async.WebAsyncUtils;
071import org.springframework.web.method.ControllerAdviceBean;
072import org.springframework.web.method.HandlerMethod;
073import org.springframework.web.method.annotation.ErrorsMethodArgumentResolver;
074import org.springframework.web.method.annotation.ExpressionValueMethodArgumentResolver;
075import org.springframework.web.method.annotation.InitBinderDataBinderFactory;
076import org.springframework.web.method.annotation.MapMethodProcessor;
077import org.springframework.web.method.annotation.ModelAttributeMethodProcessor;
078import org.springframework.web.method.annotation.ModelFactory;
079import org.springframework.web.method.annotation.ModelMethodProcessor;
080import org.springframework.web.method.annotation.RequestHeaderMapMethodArgumentResolver;
081import org.springframework.web.method.annotation.RequestHeaderMethodArgumentResolver;
082import org.springframework.web.method.annotation.RequestParamMapMethodArgumentResolver;
083import org.springframework.web.method.annotation.RequestParamMethodArgumentResolver;
084import org.springframework.web.method.annotation.SessionAttributesHandler;
085import org.springframework.web.method.annotation.SessionStatusMethodArgumentResolver;
086import org.springframework.web.method.support.HandlerMethodArgumentResolver;
087import org.springframework.web.method.support.HandlerMethodArgumentResolverComposite;
088import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
089import org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite;
090import org.springframework.web.method.support.InvocableHandlerMethod;
091import org.springframework.web.method.support.ModelAndViewContainer;
092import org.springframework.web.servlet.ModelAndView;
093import org.springframework.web.servlet.View;
094import org.springframework.web.servlet.mvc.annotation.ModelAndViewResolver;
095import org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter;
096import org.springframework.web.servlet.mvc.support.RedirectAttributes;
097import org.springframework.web.servlet.support.RequestContextUtils;
098import org.springframework.web.util.WebUtils;
099
100/**
101 * Extension of {@link AbstractHandlerMethodAdapter} that supports
102 * {@link RequestMapping @RequestMapping} annotated {@link HandlerMethod HandlerMethods}.
103 *
104 * <p>Support for custom argument and return value types can be added via
105 * {@link #setCustomArgumentResolvers} and {@link #setCustomReturnValueHandlers},
106 * or alternatively, to re-configure all argument and return value types,
107 * use {@link #setArgumentResolvers} and {@link #setReturnValueHandlers}.
108 *
109 * @author Rossen Stoyanchev
110 * @author Juergen Hoeller
111 * @since 3.1
112 * @see HandlerMethodArgumentResolver
113 * @see HandlerMethodReturnValueHandler
114 */
115public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
116                implements BeanFactoryAware, InitializingBean {
117
118        /**
119         * MethodFilter that matches {@link InitBinder @InitBinder} methods.
120         */
121        public static final MethodFilter INIT_BINDER_METHODS = method ->
122                        AnnotatedElementUtils.hasAnnotation(method, InitBinder.class);
123
124        /**
125         * MethodFilter that matches {@link ModelAttribute @ModelAttribute} methods.
126         */
127        public static final MethodFilter MODEL_ATTRIBUTE_METHODS = method ->
128                        (!AnnotatedElementUtils.hasAnnotation(method, RequestMapping.class) &&
129                                        AnnotatedElementUtils.hasAnnotation(method, ModelAttribute.class));
130
131
132        @Nullable
133        private List<HandlerMethodArgumentResolver> customArgumentResolvers;
134
135        @Nullable
136        private HandlerMethodArgumentResolverComposite argumentResolvers;
137
138        @Nullable
139        private HandlerMethodArgumentResolverComposite initBinderArgumentResolvers;
140
141        @Nullable
142        private List<HandlerMethodReturnValueHandler> customReturnValueHandlers;
143
144        @Nullable
145        private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
146
147        @Nullable
148        private List<ModelAndViewResolver> modelAndViewResolvers;
149
150        private ContentNegotiationManager contentNegotiationManager = new ContentNegotiationManager();
151
152        private List<HttpMessageConverter<?>> messageConverters;
153
154        private final List<Object> requestResponseBodyAdvice = new ArrayList<>();
155
156        @Nullable
157        private WebBindingInitializer webBindingInitializer;
158
159        private AsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor("MvcAsync");
160
161        @Nullable
162        private Long asyncRequestTimeout;
163
164        private CallableProcessingInterceptor[] callableInterceptors = new CallableProcessingInterceptor[0];
165
166        private DeferredResultProcessingInterceptor[] deferredResultInterceptors = new DeferredResultProcessingInterceptor[0];
167
168        private ReactiveAdapterRegistry reactiveAdapterRegistry = ReactiveAdapterRegistry.getSharedInstance();
169
170        private boolean ignoreDefaultModelOnRedirect = false;
171
172        private int cacheSecondsForSessionAttributeHandlers = 0;
173
174        private boolean synchronizeOnSession = false;
175
176        private SessionAttributeStore sessionAttributeStore = new DefaultSessionAttributeStore();
177
178        private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
179
180        @Nullable
181        private ConfigurableBeanFactory beanFactory;
182
183        private final Map<Class<?>, SessionAttributesHandler> sessionAttributesHandlerCache = new ConcurrentHashMap<>(64);
184
185        private final Map<Class<?>, Set<Method>> initBinderCache = new ConcurrentHashMap<>(64);
186
187        private final Map<ControllerAdviceBean, Set<Method>> initBinderAdviceCache = new LinkedHashMap<>();
188
189        private final Map<Class<?>, Set<Method>> modelAttributeCache = new ConcurrentHashMap<>(64);
190
191        private final Map<ControllerAdviceBean, Set<Method>> modelAttributeAdviceCache = new LinkedHashMap<>();
192
193
194        public RequestMappingHandlerAdapter() {
195                this.messageConverters = new ArrayList<>(4);
196                this.messageConverters.add(new ByteArrayHttpMessageConverter());
197                this.messageConverters.add(new StringHttpMessageConverter());
198                try {
199                        this.messageConverters.add(new SourceHttpMessageConverter<>());
200                }
201                catch (Error err) {
202                        // Ignore when no TransformerFactory implementation is available
203                }
204                this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
205        }
206
207
208        /**
209         * Provide resolvers for custom argument types. Custom resolvers are ordered
210         * after built-in ones. To override the built-in support for argument
211         * resolution use {@link #setArgumentResolvers} instead.
212         */
213        public void setCustomArgumentResolvers(@Nullable List<HandlerMethodArgumentResolver> argumentResolvers) {
214                this.customArgumentResolvers = argumentResolvers;
215        }
216
217        /**
218         * Return the custom argument resolvers, or {@code null}.
219         */
220        @Nullable
221        public List<HandlerMethodArgumentResolver> getCustomArgumentResolvers() {
222                return this.customArgumentResolvers;
223        }
224
225        /**
226         * Configure the complete list of supported argument types thus overriding
227         * the resolvers that would otherwise be configured by default.
228         */
229        public void setArgumentResolvers(@Nullable List<HandlerMethodArgumentResolver> argumentResolvers) {
230                if (argumentResolvers == null) {
231                        this.argumentResolvers = null;
232                }
233                else {
234                        this.argumentResolvers = new HandlerMethodArgumentResolverComposite();
235                        this.argumentResolvers.addResolvers(argumentResolvers);
236                }
237        }
238
239        /**
240         * Return the configured argument resolvers, or possibly {@code null} if
241         * not initialized yet via {@link #afterPropertiesSet()}.
242         */
243        @Nullable
244        public List<HandlerMethodArgumentResolver> getArgumentResolvers() {
245                return (this.argumentResolvers != null ? this.argumentResolvers.getResolvers() : null);
246        }
247
248        /**
249         * Configure the supported argument types in {@code @InitBinder} methods.
250         */
251        public void setInitBinderArgumentResolvers(@Nullable List<HandlerMethodArgumentResolver> argumentResolvers) {
252                if (argumentResolvers == null) {
253                        this.initBinderArgumentResolvers = null;
254                }
255                else {
256                        this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite();
257                        this.initBinderArgumentResolvers.addResolvers(argumentResolvers);
258                }
259        }
260
261        /**
262         * Return the argument resolvers for {@code @InitBinder} methods, or possibly
263         * {@code null} if not initialized yet via {@link #afterPropertiesSet()}.
264         */
265        @Nullable
266        public List<HandlerMethodArgumentResolver> getInitBinderArgumentResolvers() {
267                return (this.initBinderArgumentResolvers != null ? this.initBinderArgumentResolvers.getResolvers() : null);
268        }
269
270        /**
271         * Provide handlers for custom return value types. Custom handlers are
272         * ordered after built-in ones. To override the built-in support for
273         * return value handling use {@link #setReturnValueHandlers}.
274         */
275        public void setCustomReturnValueHandlers(@Nullable List<HandlerMethodReturnValueHandler> returnValueHandlers) {
276                this.customReturnValueHandlers = returnValueHandlers;
277        }
278
279        /**
280         * Return the custom return value handlers, or {@code null}.
281         */
282        @Nullable
283        public List<HandlerMethodReturnValueHandler> getCustomReturnValueHandlers() {
284                return this.customReturnValueHandlers;
285        }
286
287        /**
288         * Configure the complete list of supported return value types thus
289         * overriding handlers that would otherwise be configured by default.
290         */
291        public void setReturnValueHandlers(@Nullable List<HandlerMethodReturnValueHandler> returnValueHandlers) {
292                if (returnValueHandlers == null) {
293                        this.returnValueHandlers = null;
294                }
295                else {
296                        this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite();
297                        this.returnValueHandlers.addHandlers(returnValueHandlers);
298                }
299        }
300
301        /**
302         * Return the configured handlers, or possibly {@code null} if not
303         * initialized yet via {@link #afterPropertiesSet()}.
304         */
305        @Nullable
306        public List<HandlerMethodReturnValueHandler> getReturnValueHandlers() {
307                return (this.returnValueHandlers != null ? this.returnValueHandlers.getHandlers() : null);
308        }
309
310        /**
311         * Provide custom {@link ModelAndViewResolver ModelAndViewResolvers}.
312         * <p><strong>Note:</strong> This method is available for backwards
313         * compatibility only. However, it is recommended to re-write a
314         * {@code ModelAndViewResolver} as {@link HandlerMethodReturnValueHandler}.
315         * An adapter between the two interfaces is not possible since the
316         * {@link HandlerMethodReturnValueHandler#supportsReturnType} method
317         * cannot be implemented. Hence {@code ModelAndViewResolver}s are limited
318         * to always being invoked at the end after all other return value
319         * handlers have been given a chance.
320         * <p>A {@code HandlerMethodReturnValueHandler} provides better access to
321         * the return type and controller method information and can be ordered
322         * freely relative to other return value handlers.
323         */
324        public void setModelAndViewResolvers(@Nullable List<ModelAndViewResolver> modelAndViewResolvers) {
325                this.modelAndViewResolvers = modelAndViewResolvers;
326        }
327
328        /**
329         * Return the configured {@link ModelAndViewResolver ModelAndViewResolvers}, or {@code null}.
330         */
331        @Nullable
332        public List<ModelAndViewResolver> getModelAndViewResolvers() {
333                return this.modelAndViewResolvers;
334        }
335
336        /**
337         * Set the {@link ContentNegotiationManager} to use to determine requested media types.
338         * If not set, the default constructor is used.
339         */
340        public void setContentNegotiationManager(ContentNegotiationManager contentNegotiationManager) {
341                this.contentNegotiationManager = contentNegotiationManager;
342        }
343
344        /**
345         * Provide the converters to use in argument resolvers and return value
346         * handlers that support reading and/or writing to the body of the
347         * request and response.
348         */
349        public void setMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
350                this.messageConverters = messageConverters;
351        }
352
353        /**
354         * Return the configured message body converters.
355         */
356        public List<HttpMessageConverter<?>> getMessageConverters() {
357                return this.messageConverters;
358        }
359
360        /**
361         * Add one or more {@code RequestBodyAdvice} instances to intercept the
362         * request before it is read and converted for {@code @RequestBody} and
363         * {@code HttpEntity} method arguments.
364         */
365        public void setRequestBodyAdvice(@Nullable List<RequestBodyAdvice> requestBodyAdvice) {
366                if (requestBodyAdvice != null) {
367                        this.requestResponseBodyAdvice.addAll(requestBodyAdvice);
368                }
369        }
370
371        /**
372         * Add one or more {@code ResponseBodyAdvice} instances to intercept the
373         * response before {@code @ResponseBody} or {@code ResponseEntity} return
374         * values are written to the response body.
375         */
376        public void setResponseBodyAdvice(@Nullable List<ResponseBodyAdvice<?>> responseBodyAdvice) {
377                if (responseBodyAdvice != null) {
378                        this.requestResponseBodyAdvice.addAll(responseBodyAdvice);
379                }
380        }
381
382        /**
383         * Provide a WebBindingInitializer with "global" initialization to apply
384         * to every DataBinder instance.
385         */
386        public void setWebBindingInitializer(@Nullable WebBindingInitializer webBindingInitializer) {
387                this.webBindingInitializer = webBindingInitializer;
388        }
389
390        /**
391         * Return the configured WebBindingInitializer, or {@code null} if none.
392         */
393        @Nullable
394        public WebBindingInitializer getWebBindingInitializer() {
395                return this.webBindingInitializer;
396        }
397
398        /**
399         * Set the default {@link AsyncTaskExecutor} to use when a controller method
400         * return a {@link Callable}. Controller methods can override this default on
401         * a per-request basis by returning an {@link WebAsyncTask}.
402         * <p>By default a {@link SimpleAsyncTaskExecutor} instance is used.
403         * It's recommended to change that default in production as the simple executor
404         * does not re-use threads.
405         */
406        public void setTaskExecutor(AsyncTaskExecutor taskExecutor) {
407                this.taskExecutor = taskExecutor;
408        }
409
410        /**
411         * Specify the amount of time, in milliseconds, before concurrent handling
412         * should time out. In Servlet 3, the timeout begins after the main request
413         * processing thread has exited and ends when the request is dispatched again
414         * for further processing of the concurrently produced result.
415         * <p>If this value is not set, the default timeout of the underlying
416         * implementation is used.
417         * @param timeout the timeout value in milliseconds
418         */
419        public void setAsyncRequestTimeout(long timeout) {
420                this.asyncRequestTimeout = timeout;
421        }
422
423        /**
424         * Configure {@code CallableProcessingInterceptor}'s to register on async requests.
425         * @param interceptors the interceptors to register
426         */
427        public void setCallableInterceptors(List<CallableProcessingInterceptor> interceptors) {
428                this.callableInterceptors = interceptors.toArray(new CallableProcessingInterceptor[0]);
429        }
430
431        /**
432         * Configure {@code DeferredResultProcessingInterceptor}'s to register on async requests.
433         * @param interceptors the interceptors to register
434         */
435        public void setDeferredResultInterceptors(List<DeferredResultProcessingInterceptor> interceptors) {
436                this.deferredResultInterceptors = interceptors.toArray(new DeferredResultProcessingInterceptor[0]);
437        }
438
439        /**
440         * Configure the registry for reactive library types to be supported as
441         * return values from controller methods.
442         * @since 5.0.5
443         */
444        public void setReactiveAdapterRegistry(ReactiveAdapterRegistry reactiveAdapterRegistry) {
445                this.reactiveAdapterRegistry = reactiveAdapterRegistry;
446        }
447
448        /**
449         * Return the configured reactive type registry of adapters.
450         * @since 5.0
451         */
452        public ReactiveAdapterRegistry getReactiveAdapterRegistry() {
453                return this.reactiveAdapterRegistry;
454        }
455
456        /**
457         * By default the content of the "default" model is used both during
458         * rendering and redirect scenarios. Alternatively a controller method
459         * can declare a {@link RedirectAttributes} argument and use it to provide
460         * attributes for a redirect.
461         * <p>Setting this flag to {@code true} guarantees the "default" model is
462         * never used in a redirect scenario even if a RedirectAttributes argument
463         * is not declared. Setting it to {@code false} means the "default" model
464         * may be used in a redirect if the controller method doesn't declare a
465         * RedirectAttributes argument.
466         * <p>The default setting is {@code false} but new applications should
467         * consider setting it to {@code true}.
468         * @see RedirectAttributes
469         */
470        public void setIgnoreDefaultModelOnRedirect(boolean ignoreDefaultModelOnRedirect) {
471                this.ignoreDefaultModelOnRedirect = ignoreDefaultModelOnRedirect;
472        }
473
474        /**
475         * Specify the strategy to store session attributes with. The default is
476         * {@link org.springframework.web.bind.support.DefaultSessionAttributeStore},
477         * storing session attributes in the HttpSession with the same attribute
478         * name as in the model.
479         */
480        public void setSessionAttributeStore(SessionAttributeStore sessionAttributeStore) {
481                this.sessionAttributeStore = sessionAttributeStore;
482        }
483
484        /**
485         * Cache content produced by {@code @SessionAttributes} annotated handlers
486         * for the given number of seconds.
487         * <p>Possible values are:
488         * <ul>
489         * <li>-1: no generation of cache-related headers</li>
490         * <li>0 (default value): "Cache-Control: no-store" will prevent caching</li>
491         * <li>1 or higher: "Cache-Control: max-age=seconds" will ask to cache content;
492         * not advised when dealing with session attributes</li>
493         * </ul>
494         * <p>In contrast to the "cacheSeconds" property which will apply to all general
495         * handlers (but not to {@code @SessionAttributes} annotated handlers),
496         * this setting will apply to {@code @SessionAttributes} handlers only.
497         * @see #setCacheSeconds
498         * @see org.springframework.web.bind.annotation.SessionAttributes
499         */
500        public void setCacheSecondsForSessionAttributeHandlers(int cacheSecondsForSessionAttributeHandlers) {
501                this.cacheSecondsForSessionAttributeHandlers = cacheSecondsForSessionAttributeHandlers;
502        }
503
504        /**
505         * Set if controller execution should be synchronized on the session,
506         * to serialize parallel invocations from the same client.
507         * <p>More specifically, the execution of the {@code handleRequestInternal}
508         * method will get synchronized if this flag is "true". The best available
509         * session mutex will be used for the synchronization; ideally, this will
510         * be a mutex exposed by HttpSessionMutexListener.
511         * <p>The session mutex is guaranteed to be the same object during
512         * the entire lifetime of the session, available under the key defined
513         * by the {@code SESSION_MUTEX_ATTRIBUTE} constant. It serves as a
514         * safe reference to synchronize on for locking on the current session.
515         * <p>In many cases, the HttpSession reference itself is a safe mutex
516         * as well, since it will always be the same object reference for the
517         * same active logical session. However, this is not guaranteed across
518         * different servlet containers; the only 100% safe way is a session mutex.
519         * @see org.springframework.web.util.HttpSessionMutexListener
520         * @see org.springframework.web.util.WebUtils#getSessionMutex(javax.servlet.http.HttpSession)
521         */
522        public void setSynchronizeOnSession(boolean synchronizeOnSession) {
523                this.synchronizeOnSession = synchronizeOnSession;
524        }
525
526        /**
527         * Set the ParameterNameDiscoverer to use for resolving method parameter names if needed
528         * (e.g. for default attribute names).
529         * <p>Default is a {@link org.springframework.core.DefaultParameterNameDiscoverer}.
530         */
531        public void setParameterNameDiscoverer(ParameterNameDiscoverer parameterNameDiscoverer) {
532                this.parameterNameDiscoverer = parameterNameDiscoverer;
533        }
534
535        /**
536         * A {@link ConfigurableBeanFactory} is expected for resolving expressions
537         * in method argument default values.
538         */
539        @Override
540        public void setBeanFactory(BeanFactory beanFactory) {
541                if (beanFactory instanceof ConfigurableBeanFactory) {
542                        this.beanFactory = (ConfigurableBeanFactory) beanFactory;
543                }
544        }
545
546        /**
547         * Return the owning factory of this bean instance, or {@code null} if none.
548         */
549        @Nullable
550        protected ConfigurableBeanFactory getBeanFactory() {
551                return this.beanFactory;
552        }
553
554
555        @Override
556        public void afterPropertiesSet() {
557                // Do this first, it may add ResponseBody advice beans
558                initControllerAdviceCache();
559
560                if (this.argumentResolvers == null) {
561                        List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
562                        this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
563                }
564                if (this.initBinderArgumentResolvers == null) {
565                        List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
566                        this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
567                }
568                if (this.returnValueHandlers == null) {
569                        List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
570                        this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
571                }
572        }
573
574        private void initControllerAdviceCache() {
575                if (getApplicationContext() == null) {
576                        return;
577                }
578
579                List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
580
581                List<Object> requestResponseBodyAdviceBeans = new ArrayList<>();
582
583                for (ControllerAdviceBean adviceBean : adviceBeans) {
584                        Class<?> beanType = adviceBean.getBeanType();
585                        if (beanType == null) {
586                                throw new IllegalStateException("Unresolvable type for ControllerAdviceBean: " + adviceBean);
587                        }
588                        Set<Method> attrMethods = MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS);
589                        if (!attrMethods.isEmpty()) {
590                                this.modelAttributeAdviceCache.put(adviceBean, attrMethods);
591                        }
592                        Set<Method> binderMethods = MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS);
593                        if (!binderMethods.isEmpty()) {
594                                this.initBinderAdviceCache.put(adviceBean, binderMethods);
595                        }
596                        if (RequestBodyAdvice.class.isAssignableFrom(beanType) || ResponseBodyAdvice.class.isAssignableFrom(beanType)) {
597                                requestResponseBodyAdviceBeans.add(adviceBean);
598                        }
599                }
600
601                if (!requestResponseBodyAdviceBeans.isEmpty()) {
602                        this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);
603                }
604
605                if (logger.isDebugEnabled()) {
606                        int modelSize = this.modelAttributeAdviceCache.size();
607                        int binderSize = this.initBinderAdviceCache.size();
608                        int reqCount = getBodyAdviceCount(RequestBodyAdvice.class);
609                        int resCount = getBodyAdviceCount(ResponseBodyAdvice.class);
610                        if (modelSize == 0 && binderSize == 0 && reqCount == 0 && resCount == 0) {
611                                logger.debug("ControllerAdvice beans: none");
612                        }
613                        else {
614                                logger.debug("ControllerAdvice beans: " + modelSize + " @ModelAttribute, " + binderSize +
615                                                " @InitBinder, " + reqCount + " RequestBodyAdvice, " + resCount + " ResponseBodyAdvice");
616                        }
617                }
618        }
619
620        // Count all advice, including explicit registrations..
621
622        private int getBodyAdviceCount(Class<?> adviceType) {
623                List<Object> advice = this.requestResponseBodyAdvice;
624                return RequestBodyAdvice.class.isAssignableFrom(adviceType) ?
625                                RequestResponseBodyAdviceChain.getAdviceByType(advice, RequestBodyAdvice.class).size() :
626                                RequestResponseBodyAdviceChain.getAdviceByType(advice, ResponseBodyAdvice.class).size();
627        }
628
629        /**
630         * Return the list of argument resolvers to use including built-in resolvers
631         * and custom resolvers provided via {@link #setCustomArgumentResolvers}.
632         */
633        private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
634                List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>(30);
635
636                // Annotation-based argument resolution
637                resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
638                resolvers.add(new RequestParamMapMethodArgumentResolver());
639                resolvers.add(new PathVariableMethodArgumentResolver());
640                resolvers.add(new PathVariableMapMethodArgumentResolver());
641                resolvers.add(new MatrixVariableMethodArgumentResolver());
642                resolvers.add(new MatrixVariableMapMethodArgumentResolver());
643                resolvers.add(new ServletModelAttributeMethodProcessor(false));
644                resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
645                resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
646                resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
647                resolvers.add(new RequestHeaderMapMethodArgumentResolver());
648                resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
649                resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
650                resolvers.add(new SessionAttributeMethodArgumentResolver());
651                resolvers.add(new RequestAttributeMethodArgumentResolver());
652
653                // Type-based argument resolution
654                resolvers.add(new ServletRequestMethodArgumentResolver());
655                resolvers.add(new ServletResponseMethodArgumentResolver());
656                resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
657                resolvers.add(new RedirectAttributesMethodArgumentResolver());
658                resolvers.add(new ModelMethodProcessor());
659                resolvers.add(new MapMethodProcessor());
660                resolvers.add(new ErrorsMethodArgumentResolver());
661                resolvers.add(new SessionStatusMethodArgumentResolver());
662                resolvers.add(new UriComponentsBuilderMethodArgumentResolver());
663
664                // Custom arguments
665                if (getCustomArgumentResolvers() != null) {
666                        resolvers.addAll(getCustomArgumentResolvers());
667                }
668
669                // Catch-all
670                resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
671                resolvers.add(new ServletModelAttributeMethodProcessor(true));
672
673                return resolvers;
674        }
675
676        /**
677         * Return the list of argument resolvers to use for {@code @InitBinder}
678         * methods including built-in and custom resolvers.
679         */
680        private List<HandlerMethodArgumentResolver> getDefaultInitBinderArgumentResolvers() {
681                List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>(20);
682
683                // Annotation-based argument resolution
684                resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
685                resolvers.add(new RequestParamMapMethodArgumentResolver());
686                resolvers.add(new PathVariableMethodArgumentResolver());
687                resolvers.add(new PathVariableMapMethodArgumentResolver());
688                resolvers.add(new MatrixVariableMethodArgumentResolver());
689                resolvers.add(new MatrixVariableMapMethodArgumentResolver());
690                resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
691                resolvers.add(new SessionAttributeMethodArgumentResolver());
692                resolvers.add(new RequestAttributeMethodArgumentResolver());
693
694                // Type-based argument resolution
695                resolvers.add(new ServletRequestMethodArgumentResolver());
696                resolvers.add(new ServletResponseMethodArgumentResolver());
697
698                // Custom arguments
699                if (getCustomArgumentResolvers() != null) {
700                        resolvers.addAll(getCustomArgumentResolvers());
701                }
702
703                // Catch-all
704                resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
705
706                return resolvers;
707        }
708
709        /**
710         * Return the list of return value handlers to use including built-in and
711         * custom handlers provided via {@link #setReturnValueHandlers}.
712         */
713        private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
714                List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>(20);
715
716                // Single-purpose return value types
717                handlers.add(new ModelAndViewMethodReturnValueHandler());
718                handlers.add(new ModelMethodProcessor());
719                handlers.add(new ViewMethodReturnValueHandler());
720                handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters(),
721                                this.reactiveAdapterRegistry, this.taskExecutor, this.contentNegotiationManager));
722                handlers.add(new StreamingResponseBodyReturnValueHandler());
723                handlers.add(new HttpEntityMethodProcessor(getMessageConverters(),
724                                this.contentNegotiationManager, this.requestResponseBodyAdvice));
725                handlers.add(new HttpHeadersReturnValueHandler());
726                handlers.add(new CallableMethodReturnValueHandler());
727                handlers.add(new DeferredResultMethodReturnValueHandler());
728                handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));
729
730                // Annotation-based return value types
731                handlers.add(new ModelAttributeMethodProcessor(false));
732                handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),
733                                this.contentNegotiationManager, this.requestResponseBodyAdvice));
734
735                // Multi-purpose return value types
736                handlers.add(new ViewNameMethodReturnValueHandler());
737                handlers.add(new MapMethodProcessor());
738
739                // Custom return value types
740                if (getCustomReturnValueHandlers() != null) {
741                        handlers.addAll(getCustomReturnValueHandlers());
742                }
743
744                // Catch-all
745                if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {
746                        handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));
747                }
748                else {
749                        handlers.add(new ModelAttributeMethodProcessor(true));
750                }
751
752                return handlers;
753        }
754
755
756        /**
757         * Always return {@code true} since any method argument and return value
758         * type will be processed in some way. A method argument not recognized
759         * by any HandlerMethodArgumentResolver is interpreted as a request parameter
760         * if it is a simple type, or as a model attribute otherwise. A return value
761         * not recognized by any HandlerMethodReturnValueHandler will be interpreted
762         * as a model attribute.
763         */
764        @Override
765        protected boolean supportsInternal(HandlerMethod handlerMethod) {
766                return true;
767        }
768
769        @Override
770        protected ModelAndView handleInternal(HttpServletRequest request,
771                        HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
772
773                ModelAndView mav;
774                checkRequest(request);
775
776                // Execute invokeHandlerMethod in synchronized block if required.
777                if (this.synchronizeOnSession) {
778                        HttpSession session = request.getSession(false);
779                        if (session != null) {
780                                Object mutex = WebUtils.getSessionMutex(session);
781                                synchronized (mutex) {
782                                        mav = invokeHandlerMethod(request, response, handlerMethod);
783                                }
784                        }
785                        else {
786                                // No HttpSession available -> no mutex necessary
787                                mav = invokeHandlerMethod(request, response, handlerMethod);
788                        }
789                }
790                else {
791                        // No synchronization on session demanded at all...
792                        mav = invokeHandlerMethod(request, response, handlerMethod);
793                }
794
795                if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
796                        if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
797                                applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
798                        }
799                        else {
800                                prepareResponse(response);
801                        }
802                }
803
804                return mav;
805        }
806
807        /**
808         * This implementation always returns -1. An {@code @RequestMapping} method can
809         * calculate the lastModified value, call {@link WebRequest#checkNotModified(long)},
810         * and return {@code null} if the result of that call is {@code true}.
811         */
812        @Override
813        protected long getLastModifiedInternal(HttpServletRequest request, HandlerMethod handlerMethod) {
814                return -1;
815        }
816
817
818        /**
819         * Return the {@link SessionAttributesHandler} instance for the given handler type
820         * (never {@code null}).
821         */
822        private SessionAttributesHandler getSessionAttributesHandler(HandlerMethod handlerMethod) {
823                return this.sessionAttributesHandlerCache.computeIfAbsent(
824                                handlerMethod.getBeanType(),
825                                type -> new SessionAttributesHandler(type, this.sessionAttributeStore));
826        }
827
828        /**
829         * Invoke the {@link RequestMapping} handler method preparing a {@link ModelAndView}
830         * if view resolution is required.
831         * @since 4.2
832         * @see #createInvocableHandlerMethod(HandlerMethod)
833         */
834        @Nullable
835        protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
836                        HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
837
838                ServletWebRequest webRequest = new ServletWebRequest(request, response);
839                try {
840                        WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
841                        ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
842
843                        ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
844                        if (this.argumentResolvers != null) {
845                                invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
846                        }
847                        if (this.returnValueHandlers != null) {
848                                invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
849                        }
850                        invocableMethod.setDataBinderFactory(binderFactory);
851                        invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
852
853                        ModelAndViewContainer mavContainer = new ModelAndViewContainer();
854                        mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
855                        modelFactory.initModel(webRequest, mavContainer, invocableMethod);
856                        mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
857
858                        AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
859                        asyncWebRequest.setTimeout(this.asyncRequestTimeout);
860
861                        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
862                        asyncManager.setTaskExecutor(this.taskExecutor);
863                        asyncManager.setAsyncWebRequest(asyncWebRequest);
864                        asyncManager.registerCallableInterceptors(this.callableInterceptors);
865                        asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
866
867                        if (asyncManager.hasConcurrentResult()) {
868                                Object result = asyncManager.getConcurrentResult();
869                                mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
870                                asyncManager.clearConcurrentResult();
871                                LogFormatUtils.traceDebug(logger, traceOn -> {
872                                        String formatted = LogFormatUtils.formatValue(result, !traceOn);
873                                        return "Resume with async result [" + formatted + "]";
874                                });
875                                invocableMethod = invocableMethod.wrapConcurrentResult(result);
876                        }
877
878                        invocableMethod.invokeAndHandle(webRequest, mavContainer);
879                        if (asyncManager.isConcurrentHandlingStarted()) {
880                                return null;
881                        }
882
883                        return getModelAndView(mavContainer, modelFactory, webRequest);
884                }
885                finally {
886                        webRequest.requestCompleted();
887                }
888        }
889
890        /**
891         * Create a {@link ServletInvocableHandlerMethod} from the given {@link HandlerMethod} definition.
892         * @param handlerMethod the {@link HandlerMethod} definition
893         * @return the corresponding {@link ServletInvocableHandlerMethod} (or custom subclass thereof)
894         * @since 4.2
895         */
896        protected ServletInvocableHandlerMethod createInvocableHandlerMethod(HandlerMethod handlerMethod) {
897                return new ServletInvocableHandlerMethod(handlerMethod);
898        }
899
900        private ModelFactory getModelFactory(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) {
901                SessionAttributesHandler sessionAttrHandler = getSessionAttributesHandler(handlerMethod);
902                Class<?> handlerType = handlerMethod.getBeanType();
903                Set<Method> methods = this.modelAttributeCache.get(handlerType);
904                if (methods == null) {
905                        methods = MethodIntrospector.selectMethods(handlerType, MODEL_ATTRIBUTE_METHODS);
906                        this.modelAttributeCache.put(handlerType, methods);
907                }
908                List<InvocableHandlerMethod> attrMethods = new ArrayList<>();
909                // Global methods first
910                this.modelAttributeAdviceCache.forEach((controllerAdviceBean, methodSet) -> {
911                        if (controllerAdviceBean.isApplicableToBeanType(handlerType)) {
912                                Object bean = controllerAdviceBean.resolveBean();
913                                for (Method method : methodSet) {
914                                        attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
915                                }
916                        }
917                });
918                for (Method method : methods) {
919                        Object bean = handlerMethod.getBean();
920                        attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
921                }
922                return new ModelFactory(attrMethods, binderFactory, sessionAttrHandler);
923        }
924
925        private InvocableHandlerMethod createModelAttributeMethod(WebDataBinderFactory factory, Object bean, Method method) {
926                InvocableHandlerMethod attrMethod = new InvocableHandlerMethod(bean, method);
927                if (this.argumentResolvers != null) {
928                        attrMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
929                }
930                attrMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
931                attrMethod.setDataBinderFactory(factory);
932                return attrMethod;
933        }
934
935        private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception {
936                Class<?> handlerType = handlerMethod.getBeanType();
937                Set<Method> methods = this.initBinderCache.get(handlerType);
938                if (methods == null) {
939                        methods = MethodIntrospector.selectMethods(handlerType, INIT_BINDER_METHODS);
940                        this.initBinderCache.put(handlerType, methods);
941                }
942                List<InvocableHandlerMethod> initBinderMethods = new ArrayList<>();
943                // Global methods first
944                this.initBinderAdviceCache.forEach((controllerAdviceBean, methodSet) -> {
945                        if (controllerAdviceBean.isApplicableToBeanType(handlerType)) {
946                                Object bean = controllerAdviceBean.resolveBean();
947                                for (Method method : methodSet) {
948                                        initBinderMethods.add(createInitBinderMethod(bean, method));
949                                }
950                        }
951                });
952                for (Method method : methods) {
953                        Object bean = handlerMethod.getBean();
954                        initBinderMethods.add(createInitBinderMethod(bean, method));
955                }
956                return createDataBinderFactory(initBinderMethods);
957        }
958
959        private InvocableHandlerMethod createInitBinderMethod(Object bean, Method method) {
960                InvocableHandlerMethod binderMethod = new InvocableHandlerMethod(bean, method);
961                if (this.initBinderArgumentResolvers != null) {
962                        binderMethod.setHandlerMethodArgumentResolvers(this.initBinderArgumentResolvers);
963                }
964                binderMethod.setDataBinderFactory(new DefaultDataBinderFactory(this.webBindingInitializer));
965                binderMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
966                return binderMethod;
967        }
968
969        /**
970         * Template method to create a new InitBinderDataBinderFactory instance.
971         * <p>The default implementation creates a ServletRequestDataBinderFactory.
972         * This can be overridden for custom ServletRequestDataBinder subclasses.
973         * @param binderMethods {@code @InitBinder} methods
974         * @return the InitBinderDataBinderFactory instance to use
975         * @throws Exception in case of invalid state or arguments
976         */
977        protected InitBinderDataBinderFactory createDataBinderFactory(List<InvocableHandlerMethod> binderMethods)
978                        throws Exception {
979
980                return new ServletRequestDataBinderFactory(binderMethods, getWebBindingInitializer());
981        }
982
983        @Nullable
984        private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
985                        ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
986
987                modelFactory.updateModel(webRequest, mavContainer);
988                if (mavContainer.isRequestHandled()) {
989                        return null;
990                }
991                ModelMap model = mavContainer.getModel();
992                ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
993                if (!mavContainer.isViewReference()) {
994                        mav.setView((View) mavContainer.getView());
995                }
996                if (model instanceof RedirectAttributes) {
997                        Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
998                        HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
999                        if (request != null) {
1000                                RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
1001                        }
1002                }
1003                return mav;
1004        }
1005
1006}