Many http clients pass an array to queryString in this form:
?attributes[]=field1&attributes[]=field2
I’m trying to get Controller to work with this format through RequestParam:
@RestController
public class FooController {
@RequestMapping(method = RequestMethod.GET,
value = "/foo",
produces = "application/json")
ResponseEntity<FooDto> getFoo(@RequestParam(value = "attributes", required = false) List<String> attributes) {
}
}
However, when executing a request, null is passed to the controller method as the attributes value.
I found that the “RequestParamMethodArgumentResolver.resolveName” method receives “attributes” as the value of the parameter name, while this parameter is stored in the request object using the key “attributes[]”. Therefore, the argument of the controller method is null, because resolver cannot find a match.
My questions:
- maybe spring mvc has support for this format “attributes[]=field1&attributes[]=field2” when using @RequestParam? WebDataBinder#adaptEmptyArrayIndices support it
- I tried to write an extension for RequestParamMethodArgumentResolver. Is it correct to place such logic in the resolver itself?
@Component
public class SpringMvcConfig implements WebMvcRegistrations {
@Override
public RequestMappingHandlerAdapter getRequestMappingHandlerAdapter() {
return new CustomRequestMappingHandlerAdapter();
}
public static class CustomRequestMappingHandlerAdapter extends RequestMappingHandlerAdapter {
@Override
public void setArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
log.info("setArgumentResolvers");
var list1 = new ArrayList<>(argumentResolvers);
OptionalInt index = IntStream.range(0, list1.size())
.filter(i -> {
var resolver = list1.get(i);
return !(resolver instanceof RequestParamMethodArgumentResolver
&& !(resolver instanceof CustomRequestParamMethodArgumentResolver));
})
.findFirst();
var customResolver = new CustomRequestParamMethodArgumentResolver(getBeanFactory(), false);
list1.set(index.orElse(0), customResolver);
super.setArgumentResolvers(list1);
}
}
@Slf4j
public static class CustomRequestParamMethodArgumentResolver extends RequestParamMethodArgumentResolver {
public CustomRequestParamMethodArgumentResolver(boolean useDefaultResolution) {
super(useDefaultResolution);
}
public CustomRequestParamMethodArgumentResolver(
ConfigurableBeanFactory beanFactory, boolean useDefaultResolution) {
super(beanFactory, useDefaultResolution);
}
@Override
public boolean supportsParameter(MethodParameter parameter) {
return super.supportsParameter(parameter);
}
@Override
protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
if (
(List.class.isAssignableFrom(parameter.getParameterType()) ||
Set.class.isAssignableFrom(parameter.getParameterType()))
&& (request.getParameterMap().containsKey(name + "[]"))) {
return super.resolveName(name + "[]", parameter, request);
}
return super.resolveName(name, parameter, request);
}
}
}