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