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