1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
102
103
104
105
106
107
108
109
110
111
112
113
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);
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
187
188
189
190 public void setCustomArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
191 this.customArgumentResolvers = argumentResolvers;
192 }
193
194
195
196
197 public List<HandlerMethodArgumentResolver> getCustomArgumentResolvers() {
198 return this.customArgumentResolvers;
199 }
200
201
202
203
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
217
218
219 public List<HandlerMethodArgumentResolver> getArgumentResolvers() {
220 return (this.argumentResolvers != null) ? this.argumentResolvers.getResolvers() : null;
221 }
222
223
224
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
238
239
240 public List<HandlerMethodArgumentResolver> getInitBinderArgumentResolvers() {
241 return (this.initBinderArgumentResolvers != null) ? this.initBinderArgumentResolvers.getResolvers() : null;
242 }
243
244
245
246
247
248
249 public void setCustomReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
250 this.customReturnValueHandlers = returnValueHandlers;
251 }
252
253
254
255
256 public List<HandlerMethodReturnValueHandler> getCustomReturnValueHandlers() {
257 return this.customReturnValueHandlers;
258 }
259
260
261
262
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
276
277
278 public List<HandlerMethodReturnValueHandler> getReturnValueHandlers() {
279 return this.returnValueHandlers.getHandlers();
280 }
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296 public void setModelAndViewResolvers(List<ModelAndViewResolver> modelAndViewResolvers) {
297 this.modelAndViewResolvers = modelAndViewResolvers;
298 }
299
300
301
302
303 public List<ModelAndViewResolver> getModelAndViewResolvers() {
304 return modelAndViewResolvers;
305 }
306
307
308
309
310
311 public void setContentNegotiationManager(ContentNegotiationManager contentNegotiationManager) {
312 this.contentNegotiationManager = contentNegotiationManager;
313 }
314
315
316
317
318
319
320 public void setMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
321 this.messageConverters = messageConverters;
322 }
323
324
325
326
327 public List<HttpMessageConverter<?>> getMessageConverters() {
328 return this.messageConverters;
329 }
330
331
332
333
334
335
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
346
347
348 public void setWebBindingInitializer(WebBindingInitializer webBindingInitializer) {
349 this.webBindingInitializer = webBindingInitializer;
350 }
351
352
353
354
355 public WebBindingInitializer getWebBindingInitializer() {
356 return this.webBindingInitializer;
357 }
358
359
360
361
362
363
364
365
366
367 public void setTaskExecutor(AsyncTaskExecutor taskExecutor) {
368 this.taskExecutor = taskExecutor;
369 }
370
371
372
373
374
375
376
377
378
379
380 public void setAsyncRequestTimeout(long timeout) {
381 this.asyncRequestTimeout = timeout;
382 }
383
384
385
386
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
395
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
404
405
406
407
408
409
410
411
412
413
414
415
416 public void setIgnoreDefaultModelOnRedirect(boolean ignoreDefaultModelOnRedirect) {
417 this.ignoreDefaultModelOnRedirect = ignoreDefaultModelOnRedirect;
418 }
419
420
421
422
423
424
425
426 public void setSessionAttributeStore(SessionAttributeStore sessionAttributeStore) {
427 this.sessionAttributeStore = sessionAttributeStore;
428 }
429
430
431
432
433
434
435
436
437
438
439 public void setCacheSecondsForSessionAttributeHandlers(int cacheSecondsForSessionAttributeHandlers) {
440 this.cacheSecondsForSessionAttributeHandlers = cacheSecondsForSessionAttributeHandlers;
441 }
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461 public void setSynchronizeOnSession(boolean synchronizeOnSession) {
462 this.synchronizeOnSession = synchronizeOnSession;
463 }
464
465
466
467
468
469
470 public void setParameterNameDiscoverer(ParameterNameDiscoverer parameterNameDiscoverer) {
471 this.parameterNameDiscoverer = parameterNameDiscoverer;
472 }
473
474
475
476
477
478 @Override
479 public void setBeanFactory(BeanFactory beanFactory) {
480 if (beanFactory instanceof ConfigurableBeanFactory) {
481 this.beanFactory = (ConfigurableBeanFactory) beanFactory;
482 }
483 }
484
485
486
487
488 protected ConfigurableBeanFactory getBeanFactory() {
489 return this.beanFactory;
490 }
491
492
493 @Override
494 public void afterPropertiesSet() {
495
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
549
550
551 private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
552 List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();
553
554
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
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
581 if (getCustomArgumentResolvers() != null) {
582 resolvers.addAll(getCustomArgumentResolvers());
583 }
584
585
586 resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
587 resolvers.add(new ServletModelAttributeMethodProcessor(true));
588
589 return resolvers;
590 }
591
592
593
594
595
596 private List<HandlerMethodArgumentResolver> getDefaultInitBinderArgumentResolvers() {
597 List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();
598
599
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
609 resolvers.add(new ServletRequestMethodArgumentResolver());
610 resolvers.add(new ServletResponseMethodArgumentResolver());
611
612
613 if (getCustomArgumentResolvers() != null) {
614 resolvers.addAll(getCustomArgumentResolvers());
615 }
616
617
618 resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
619
620 return resolvers;
621 }
622
623
624
625
626
627 private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
628 List<HandlerMethodReturnValueHandler> handlers = new ArrayList<HandlerMethodReturnValueHandler>();
629
630
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
643 handlers.add(new ModelAttributeMethodProcessor(false));
644 handlers.add(new RequestResponseBodyMethodProcessor(
645 getMessageConverters(), this.contentNegotiationManager, this.responseBodyAdvice));
646
647
648 handlers.add(new ViewNameMethodReturnValueHandler());
649 handlers.add(new MapMethodProcessor());
650
651
652 if (getCustomReturnValueHandlers() != null) {
653 handlers.addAll(getCustomReturnValueHandlers());
654 }
655
656
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
670
671
672
673
674
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
687 checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
688 }
689 else {
690
691 checkAndPrepare(request, response, true);
692 }
693
694
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
710
711
712
713 @Override
714 protected long getLastModifiedInternal(HttpServletRequest request, HandlerMethod handlerMethod) {
715 return -1;
716 }
717
718
719
720
721
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
740
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
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
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
864
865
866
867
868
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
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
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 }