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.support; 018 019import java.util.Collections; 020import java.util.LinkedList; 021import java.util.List; 022import java.util.Map; 023import java.util.concurrent.ConcurrentHashMap; 024 025import org.apache.commons.logging.Log; 026import org.apache.commons.logging.LogFactory; 027 028import org.springframework.core.MethodParameter; 029import org.springframework.web.bind.support.WebDataBinderFactory; 030import org.springframework.web.context.request.NativeWebRequest; 031 032/** 033 * Resolves method parameters by delegating to a list of registered 034 * {@link HandlerMethodArgumentResolver HandlerMethodArgumentResolvers}. 035 * Previously resolved method parameters are cached for faster lookups. 036 * 037 * @author Rossen Stoyanchev 038 * @author Juergen Hoeller 039 * @since 3.1 040 */ 041public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver { 042 043 @Deprecated 044 protected final Log logger = LogFactory.getLog(getClass()); 045 046 private final List<HandlerMethodArgumentResolver> argumentResolvers = 047 new LinkedList<HandlerMethodArgumentResolver>(); 048 049 private final Map<MethodParameter, HandlerMethodArgumentResolver> argumentResolverCache = 050 new ConcurrentHashMap<MethodParameter, HandlerMethodArgumentResolver>(256); 051 052 053 /** 054 * Add the given {@link HandlerMethodArgumentResolver}. 055 */ 056 public HandlerMethodArgumentResolverComposite addResolver(HandlerMethodArgumentResolver resolver) { 057 this.argumentResolvers.add(resolver); 058 return this; 059 } 060 061 /** 062 * Add the given {@link HandlerMethodArgumentResolver HandlerMethodArgumentResolvers}. 063 * @since 4.3 064 */ 065 public HandlerMethodArgumentResolverComposite addResolvers(HandlerMethodArgumentResolver... resolvers) { 066 if (resolvers != null) { 067 Collections.addAll(this.argumentResolvers, resolvers); 068 } 069 return this; 070 } 071 072 /** 073 * Add the given {@link HandlerMethodArgumentResolver HandlerMethodArgumentResolvers}. 074 */ 075 public HandlerMethodArgumentResolverComposite addResolvers(List<? extends HandlerMethodArgumentResolver> resolvers) { 076 if (resolvers != null) { 077 this.argumentResolvers.addAll(resolvers); 078 } 079 return this; 080 } 081 082 /** 083 * Return a read-only list with the contained resolvers, or an empty list. 084 */ 085 public List<HandlerMethodArgumentResolver> getResolvers() { 086 return Collections.unmodifiableList(this.argumentResolvers); 087 } 088 089 /** 090 * Clear the list of configured resolvers. 091 * @since 4.3 092 */ 093 public void clear() { 094 this.argumentResolvers.clear(); 095 } 096 097 098 /** 099 * Whether the given {@linkplain MethodParameter method parameter} is 100 * supported by any registered {@link HandlerMethodArgumentResolver}. 101 */ 102 @Override 103 public boolean supportsParameter(MethodParameter parameter) { 104 return getArgumentResolver(parameter) != null; 105 } 106 107 /** 108 * Iterate over registered 109 * {@link HandlerMethodArgumentResolver HandlerMethodArgumentResolvers} 110 * and invoke the one that supports it. 111 * @throws IllegalArgumentException if no suitable argument resolver is found 112 */ 113 @Override 114 public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, 115 NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { 116 117 HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter); 118 if (resolver == null) { 119 throw new IllegalArgumentException("Unsupported parameter type [" + 120 parameter.getParameterType().getName() + "]. supportsParameter should be called first."); 121 } 122 return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory); 123 } 124 125 /** 126 * Find a registered {@link HandlerMethodArgumentResolver} that supports 127 * the given method parameter. 128 */ 129 private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) { 130 HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter); 131 if (result == null) { 132 for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) { 133 if (resolver.supportsParameter(parameter)) { 134 result = resolver; 135 this.argumentResolverCache.put(parameter, result); 136 break; 137 } 138 } 139 } 140 return result; 141 } 142 143}