public Map<String, Object> method(@NotNull List<String> list){
//your code
}
在開發中, 遇到某些場景需要傳入一個集合參數, 當我理所應當的寫出上述代碼, 並且進行調試的時候, 卻出現了和意料中不一樣的結果:
HTTP Status 500 - Request processing failed;
nested exception is org.springframework.beans.BeanInstantiationException:
Failed to instantiate [java.util.List]: Specified class is an interface
原來如此, 原來List是一個接口, 那么我換成實現就應該好了, 於是將代碼修改為:
public Map<String, Object> method(@NotNull ArrayList<String> list){
//your code
}
當我使用swagger接口文檔進行調試, 輸入以下參數

這下應該好了吧, 但是實際上和我想的還是不一樣, 接口調用不報錯了, 但是:

接口中的參數是一個空集合, 經過胡亂探索發現, 在參數上做一點小改動就可以達到正確傳入:
public Map<String, Object> method(@NotNull @RequestParam List<String> list){
//your code
}
效果圖:

但是為什么?, 通過跟蹤源碼發現, 存在一個參數解析的過程, 不同的注解使用不同的解析器來解析, 其中這篇文章對我的啟發很大, 推薦大家看看
https://www.2cto.com/kf/201405/301660.html
經過追蹤分析源碼, 比對存在@RequestParam和不存在的情況, 發現參數解析是一種嘗試行為, 如果能解析出來, 那么正確賦值. 下面特出關鍵源碼, 源碼類為:
org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver
代碼如下:
@Override
public final Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
Class<?> paramType = parameter.getParameterType();
NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
//從request中獲取參數
Object arg = resolveName(namedValueInfo.name, parameter, webRequest);
if (arg == null) {
if (namedValueInfo.defaultValue != null) {
arg = resolveDefaultValue(namedValueInfo.defaultValue);
}
else if (namedValueInfo.required && !parameter.getParameterType().getName().equals("java.util.Optional")) {
handleMissingValue(namedValueInfo.name, parameter);
}
arg = handleNullValue(namedValueInfo.name, arg, paramType);
}
else if ("".equals(arg) && namedValueInfo.defaultValue != null) {
arg = resolveDefaultValue(namedValueInfo.defaultValue);
}
//如果綁定處理工廠不是空, 嘗試進行參數解析, 這里將會正確的將list參數解析為list, 本例中如果不加Requestparam那么是不會進入的.
if (binderFactory != null) {
WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
try {
arg = binder.convertIfNecessary(arg, paramType, parameter);
}
catch (ConversionNotSupportedException ex) {
throw new MethodArgumentConversionNotSupportedException(arg, ex.getRequiredType(),
namedValueInfo.name, parameter, ex.getCause());
}
catch (TypeMismatchException ex) {
throw new MethodArgumentTypeMismatchException(arg, ex.getRequiredType(),
namedValueInfo.name, parameter, ex.getCause());
}
}
handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);
return arg;
}
至此, 知其所以然. mark一下
