Affects: spring-web 5.2.11


Given a controller like the following:

import javax.annotation.Nullable;

import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/path")
public class MyController {

    private static class MyCriteria {

        @Nullable
        private String param1;

        @Nullable
        private MultiValueMap<String, String> otherParams;

        // getters and setter omitted
    }

    @GetMapping
    public void getByCriteria(MyCriteria criteria) {
        // body
    }
}

I would expect a GET request to /path?param1=a&otherParams[otherParam]=b to cause an instance of MyCriteria with param1 = "a" and otherParams = {"otherParam": ["b"]} to be passed in.

Instead, the following exception is thrown:

java.lang.ClassCastException: class java.lang.String cannot be cast to class java.util.List (java.lang.String and java.util.List are in module java.base of loader 'bootstrap')
    at org.springframework.util.LinkedMultiValueMap.put(LinkedMultiValueMap.java:42)
    at org.springframework.beans.AbstractNestablePropertyAccessor.processKeyedProperty(AbstractNestablePropertyAccessor.java:371)
    at org.springframework.beans.AbstractNestablePropertyAccessor.setPropertyValue(AbstractNestablePropertyAccessor.java:275)
    at org.springframework.beans.AbstractNestablePropertyAccessor.setPropertyValue(AbstractNestablePropertyAccessor.java:266)
    at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:104)
    at org.springframework.validation.DataBinder.applyPropertyValues(DataBinder.java:848)
    at org.springframework.validation.DataBinder.doBind(DataBinder.java:744)
    at org.springframework.web.bind.WebDataBinder.doBind(WebDataBinder.java:197)
    at org.springframework.web.bind.ServletRequestDataBinder.bind(ServletRequestDataBinder.java:107)

This works as expected when MultiValueMap<String, String> is replaced with Map<String, List<String>>

Comment From: jhoeller

MultiValueMap value type detection does not seem to work in the core BeanWrapper infrastructure underneath such a web data binding attempt, whereas it does work for a generically typed Map with explicit collection values. We'll revisit this for 5.3.3, with an intent for a 5.2.13 backport.

Comment From: jhoeller

This turns out to be rather involved and simply not covered by our general Map support in the core BeanWrapper infrastructure. We can certainly support MultiValueMap specifically in separate code paths but this is only likely to materialize in 5.3.x at this point.

Comment From: jhoeller

Finally coming into 6.1 through a revised PropertyHandler arrangement where we resolve map value types as a TypeDescriptor now, introspecting the actual Map generics and not the top-level generics on MultiValueMap.