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