001/* 002 * Copyright 2002-2018 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.ModelMap; 022import org.springframework.util.Assert; 023import org.springframework.util.CollectionUtils; 024import org.springframework.validation.BindingResult; 025import org.springframework.validation.Errors; 026import org.springframework.web.bind.support.WebDataBinderFactory; 027import org.springframework.web.context.request.NativeWebRequest; 028import org.springframework.web.method.support.HandlerMethodArgumentResolver; 029import org.springframework.web.method.support.ModelAndViewContainer; 030 031/** 032 * Resolves {@link Errors} method arguments. 033 * 034 * <p>An {@code Errors} method argument is expected to appear immediately after 035 * the model attribute in the method signature. It is resolved by expecting the 036 * last two attributes added to the model to be the model attribute and its 037 * {@link BindingResult}. 038 * 039 * @author Rossen Stoyanchev 040 * @author Juergen Hoeller 041 * @since 3.1 042 */ 043public class ErrorsMethodArgumentResolver implements HandlerMethodArgumentResolver { 044 045 @Override 046 public boolean supportsParameter(MethodParameter parameter) { 047 Class<?> paramType = parameter.getParameterType(); 048 return Errors.class.isAssignableFrom(paramType); 049 } 050 051 @Override 052 @Nullable 053 public Object resolveArgument(MethodParameter parameter, 054 @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, 055 @Nullable WebDataBinderFactory binderFactory) throws Exception { 056 057 Assert.state(mavContainer != null, 058 "Errors/BindingResult argument only supported on regular handler methods"); 059 060 ModelMap model = mavContainer.getModel(); 061 String lastKey = CollectionUtils.lastElement(model.keySet()); 062 if (lastKey != null && lastKey.startsWith(BindingResult.MODEL_KEY_PREFIX)) { 063 return model.get(lastKey); 064 } 065 066 throw new IllegalStateException( 067 "An Errors/BindingResult argument is expected to be declared immediately after " + 068 "the model attribute, the @RequestBody or the @RequestPart arguments " + 069 "to which they apply: " + parameter.getMethod()); 070 } 071 072}