001/* 002 * Copyright 2002-2014 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.List; 021 022import org.springframework.core.MethodParameter; 023import org.springframework.ui.ExtendedModelMap; 024import org.springframework.web.context.request.NativeWebRequest; 025import org.springframework.web.method.annotation.ModelAttributeMethodProcessor; 026import org.springframework.web.method.support.HandlerMethodReturnValueHandler; 027import org.springframework.web.method.support.ModelAndViewContainer; 028import org.springframework.web.servlet.ModelAndView; 029import org.springframework.web.servlet.mvc.annotation.ModelAndViewResolver; 030 031/** 032 * This return value handler is intended to be ordered after all others as it 033 * attempts to handle _any_ return value type (i.e. returns {@code true} for 034 * all return types). 035 * 036 * <p>The return value is handled either with a {@link ModelAndViewResolver} 037 * or otherwise by regarding it as a model attribute if it is a non-simple 038 * type. If neither of these succeeds (essentially simple type other than 039 * String), {@link UnsupportedOperationException} is raised. 040 * 041 * <p><strong>Note:</strong> This class is primarily needed to support 042 * {@link ModelAndViewResolver}, which unfortunately cannot be properly 043 * adapted to the {@link HandlerMethodReturnValueHandler} contract since the 044 * {@link HandlerMethodReturnValueHandler#supportsReturnType} method 045 * cannot be implemented. Hence {@code ModelAndViewResolver}s are limited 046 * to always being invoked at the end after all other return value 047 * handlers have been given a chance. It is recommended to re-implement 048 * a {@code ModelAndViewResolver} as {@code HandlerMethodReturnValueHandler}, 049 * which also provides better access to the return type and method information. 050 * 051 * @author Rossen Stoyanchev 052 * @since 3.1 053 */ 054public class ModelAndViewResolverMethodReturnValueHandler implements HandlerMethodReturnValueHandler { 055 056 private final List<ModelAndViewResolver> mavResolvers; 057 058 private final ModelAttributeMethodProcessor modelAttributeProcessor = new ModelAttributeMethodProcessor(true); 059 060 061 /** 062 * Create a new instance. 063 */ 064 public ModelAndViewResolverMethodReturnValueHandler(List<ModelAndViewResolver> mavResolvers) { 065 this.mavResolvers = mavResolvers; 066 } 067 068 069 /** 070 * Always returns {@code true}. See class-level note. 071 */ 072 @Override 073 public boolean supportsReturnType(MethodParameter returnType) { 074 return true; 075 } 076 077 @Override 078 public void handleReturnValue(Object returnValue, MethodParameter returnType, 079 ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { 080 081 if (this.mavResolvers != null) { 082 for (ModelAndViewResolver mavResolver : this.mavResolvers) { 083 Class<?> handlerType = returnType.getContainingClass(); 084 Method method = returnType.getMethod(); 085 ExtendedModelMap model = (ExtendedModelMap) mavContainer.getModel(); 086 ModelAndView mav = mavResolver.resolveModelAndView(method, handlerType, returnValue, model, webRequest); 087 if (mav != ModelAndViewResolver.UNRESOLVED) { 088 mavContainer.addAllAttributes(mav.getModel()); 089 mavContainer.setViewName(mav.getViewName()); 090 if (!mav.isReference()) { 091 mavContainer.setView(mav.getView()); 092 } 093 return; 094 } 095 } 096 } 097 098 // No suitable ModelAndViewResolver... 099 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}