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