001/* 002 * Copyright 2002-2019 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.apache.commons.logging.Log; 020import org.apache.commons.logging.LogFactory; 021 022import org.springframework.core.MethodParameter; 023import org.springframework.lang.Nullable; 024import org.springframework.util.Assert; 025import org.springframework.util.ClassUtils; 026import org.springframework.web.bind.support.WebArgumentResolver; 027import org.springframework.web.bind.support.WebDataBinderFactory; 028import org.springframework.web.context.request.NativeWebRequest; 029import org.springframework.web.method.support.HandlerMethodArgumentResolver; 030import org.springframework.web.method.support.ModelAndViewContainer; 031 032/** 033 * An abstract base class adapting a {@link WebArgumentResolver} to the 034 * {@link HandlerMethodArgumentResolver} contract. 035 * 036 * <p><strong>Note:</strong> This class is provided for backwards compatibility. 037 * However it is recommended to re-write a {@code WebArgumentResolver} as 038 * {@code HandlerMethodArgumentResolver}. Since {@link #supportsParameter} 039 * can only be implemented by actually resolving the value and then checking 040 * the result is not {@code WebArgumentResolver#UNRESOLVED} any exceptions 041 * raised must be absorbed and ignored since it's not clear whether the adapter 042 * doesn't support the parameter or whether it failed for an internal reason. 043 * The {@code HandlerMethodArgumentResolver} contract also provides access to 044 * model attributes and to {@code WebDataBinderFactory} (for type conversion). 045 * 046 * @author Arjen Poutsma 047 * @author Rossen Stoyanchev 048 * @since 3.1 049 */ 050public abstract class AbstractWebArgumentResolverAdapter implements HandlerMethodArgumentResolver { 051 052 private final Log logger = LogFactory.getLog(getClass()); 053 054 private final WebArgumentResolver adaptee; 055 056 057 /** 058 * Create a new instance. 059 */ 060 public AbstractWebArgumentResolverAdapter(WebArgumentResolver adaptee) { 061 Assert.notNull(adaptee, "'adaptee' must not be null"); 062 this.adaptee = adaptee; 063 } 064 065 066 /** 067 * Actually resolve the value and check the resolved value is not 068 * {@link WebArgumentResolver#UNRESOLVED} absorbing _any_ exceptions. 069 */ 070 @Override 071 public boolean supportsParameter(MethodParameter parameter) { 072 try { 073 NativeWebRequest webRequest = getWebRequest(); 074 Object result = this.adaptee.resolveArgument(parameter, webRequest); 075 if (result == WebArgumentResolver.UNRESOLVED) { 076 return false; 077 } 078 else { 079 return ClassUtils.isAssignableValue(parameter.getParameterType(), result); 080 } 081 } 082 catch (Exception ex) { 083 // ignore (see class-level doc) 084 if (logger.isDebugEnabled()) { 085 logger.debug("Error in checking support for parameter [" + parameter + "]: " + ex.getMessage()); 086 } 087 return false; 088 } 089 } 090 091 /** 092 * Delegate to the {@link WebArgumentResolver} instance. 093 * @throws IllegalStateException if the resolved value is not assignable 094 * to the method parameter. 095 */ 096 @Override 097 @Nullable 098 public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, 099 NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { 100 101 Class<?> paramType = parameter.getParameterType(); 102 Object result = this.adaptee.resolveArgument(parameter, webRequest); 103 if (result == WebArgumentResolver.UNRESOLVED || !ClassUtils.isAssignableValue(paramType, result)) { 104 throw new IllegalStateException( 105 "Standard argument type [" + paramType.getName() + "] in method " + parameter.getMethod() + 106 "resolved to incompatible value of type [" + (result != null ? result.getClass() : null) + 107 "]. Consider declaring the argument type in a less specific fashion."); 108 } 109 return result; 110 } 111 112 113 /** 114 * Required for access to NativeWebRequest in {@link #supportsParameter}. 115 */ 116 protected abstract NativeWebRequest getWebRequest(); 117 118}