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一下
