001/* 002 * Copyright 2002-2020 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.method.annotation; 018 019import org.springframework.core.MethodParameter; 020import org.springframework.lang.Nullable; 021import org.springframework.ui.Model; 022import org.springframework.util.Assert; 023import org.springframework.web.bind.support.WebDataBinderFactory; 024import org.springframework.web.context.request.NativeWebRequest; 025import org.springframework.web.method.support.HandlerMethodArgumentResolver; 026import org.springframework.web.method.support.HandlerMethodReturnValueHandler; 027import org.springframework.web.method.support.ModelAndViewContainer; 028 029/** 030 * Resolves {@link Model} arguments and handles {@link Model} return values. 031 * 032 * <p>A {@link Model} return type has a set purpose. Therefore this handler 033 * should be configured ahead of handlers that support any return value type 034 * annotated with {@code @ModelAttribute} or {@code @ResponseBody} to ensure 035 * they don't take over. 036 * 037 * @author Rossen Stoyanchev 038 * @since 3.1 039 */ 040public class ModelMethodProcessor implements HandlerMethodArgumentResolver, HandlerMethodReturnValueHandler { 041 042 @Override 043 public boolean supportsParameter(MethodParameter parameter) { 044 return Model.class.isAssignableFrom(parameter.getParameterType()); 045 } 046 047 @Override 048 @Nullable 049 public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, 050 NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { 051 052 Assert.state(mavContainer != null, "ModelAndViewContainer is required for model exposure"); 053 return mavContainer.getModel(); 054 } 055 056 @Override 057 public boolean supportsReturnType(MethodParameter returnType) { 058 return Model.class.isAssignableFrom(returnType.getParameterType()); 059 } 060 061 @Override 062 public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, 063 ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { 064 065 if (returnValue == null) { 066 return; 067 } 068 else if (returnValue instanceof Model) { 069 mavContainer.addAllAttributes(((Model) returnValue).asMap()); 070 } 071 else { 072 // should not happen 073 throw new UnsupportedOperationException("Unexpected return type [" + 074 returnType.getParameterType().getName() + "] in method: " + returnType.getMethod()); 075 } 076 } 077 078}