Description
Affects: 6.1.6
This is a slight variation of SPR-17340 (#21874) that I've run into.
I have a Payload
class that derives from Map<String, Object>
:
public class Payload extends HashMap<String, Object> {
// some convenience methods here
}
And a method argument resolver for it:
public class PayloadMethodArgumentResolver extends RequestResponseBodyMethodProcessor {
...
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterType().equals(Payload.class);
}
...
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
Payload payload = new Payload();
...
return payload;
}
}
I want to use it like this:
@PostMapping("/host")
public ResponseEntity<?> createHost(Payload values) {
...
}
Note that there is no annotation before Payload
(it should not be necessary, since we have a custom type with a custom argument resolver. But, since there is no way to add my resolver to the top of the resolver list (org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.getDefaultArgumentResolvers()
), the MapMethodProcessor
will be used, returning an empty BindingAwareModelMap
. Since this does not match the required type of createHost
, an IllegalArgumentException
will be thrown in org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(Object...)
.
I think the problem lies in org.springframework.web.method.annotation.MapMethodProcessor.supportsParameter(MethodParameter)
, which should not claim support for every subtype of Map (as it currently does). If the type check would be flipped like this, I think it should work correctly:
@Override
public boolean supportsParameter(MethodParameter parameter) {
return (parameter.getParameterType().isAssignableFrom(Map.class) &&
parameter.getParameterAnnotations().length == 0);
}
Only if the type of the parameter can be assigned a Map
should the MapMethodProcessor
be applied.