View Javadoc
1   /*
2    * Copyright 2002-2014 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.List;
21  
22  import org.springframework.core.MethodParameter;
23  import org.springframework.ui.ExtendedModelMap;
24  import org.springframework.web.context.request.NativeWebRequest;
25  import org.springframework.web.method.annotation.ModelAttributeMethodProcessor;
26  import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
27  import org.springframework.web.method.support.ModelAndViewContainer;
28  import org.springframework.web.servlet.ModelAndView;
29  import org.springframework.web.servlet.mvc.annotation.ModelAndViewResolver;
30  
31  /**
32   * This return value handler is intended to be ordered after all others as it
33   * attempts to handle _any_ return value type (i.e. returns {@code true} for
34   * all return types).
35   *
36   * <p>The return value is handled either with a {@link ModelAndViewResolver}
37   * or otherwise by regarding it as a model attribute if it is a non-simple
38   * type. If neither of these succeeds (essentially simple type other than
39   * String), {@link UnsupportedOperationException} is raised.
40   *
41   * <p><strong>Note:</strong> This class is primarily needed to support
42   * {@link ModelAndViewResolver}, which unfortunately cannot be properly
43   * adapted to the {@link HandlerMethodReturnValueHandler} contract since the
44   * {@link HandlerMethodReturnValueHandler#supportsReturnType} method
45   * cannot be implemented. Hence {@code ModelAndViewResolver}s are limited
46   * to always being invoked at the end after all other return value
47   * handlers have been given a chance. It is recommended to re-implement
48   * a {@code ModelAndViewResolver} as {@code HandlerMethodReturnValueHandler},
49   * which also provides better access to the return type and method information.
50   *
51   * @author Rossen Stoyanchev
52   * @since 3.1
53   */
54  public class ModelAndViewResolverMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
55  
56  	private final List<ModelAndViewResolver> mavResolvers;
57  
58  	private final ModelAttributeMethodProcessor modelAttributeProcessor = new ModelAttributeMethodProcessor(true);
59  
60  
61  	/**
62  	 * Create a new instance.
63  	 */
64  	public ModelAndViewResolverMethodReturnValueHandler(List<ModelAndViewResolver> mavResolvers) {
65  		this.mavResolvers = mavResolvers;
66  	}
67  
68  
69  	/**
70  	 * Always returns {@code true}. See class-level note.
71  	 */
72  	@Override
73  	public boolean supportsReturnType(MethodParameter returnType) {
74  		return true;
75  	}
76  
77  	@Override
78  	public void handleReturnValue(Object returnValue, MethodParameter returnType,
79  			ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
80  
81  		if (this.mavResolvers != null) {
82  			for (ModelAndViewResolver mavResolver : this.mavResolvers) {
83  				Class<?> handlerType = returnType.getContainingClass();
84  				Method method = returnType.getMethod();
85  				ExtendedModelMap model = (ExtendedModelMap) mavContainer.getModel();
86  				ModelAndView mav = mavResolver.resolveModelAndView(method, handlerType, returnValue, model, webRequest);
87  				if (mav != ModelAndViewResolver.UNRESOLVED) {
88  					mavContainer.addAllAttributes(mav.getModel());
89  					mavContainer.setViewName(mav.getViewName());
90  					if (!mav.isReference()) {
91  						mavContainer.setView(mav.getView());
92  					}
93  					return;
94  				}
95  			}
96  		}
97  
98  		// No suitable ModelAndViewResolver...
99  		if (this.modelAttributeProcessor.supportsReturnType(returnType)) {
100 			this.modelAttributeProcessor.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
101 		}
102 		else {
103 			throw new UnsupportedOperationException("Unexpected return type: " +
104 					returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
105 		}
106 	}
107 
108 }