[FIXED] Using a MultiMap on spring boot controller


I have the following payload:

    "KeyA": "ValueA",
    "KeyB": "ValueB",
    "KeyC": "ValueC"
    "KeyZ": "ValueZ"

That I am able to parse properly in a spring boot controller with:

  public ResponseEntity<Object> createABC(
      @RequestBody final Map<MyDTO, MyDTO> map
  ) {

For the sake of brevity, consider MyDTO as:

public class MyDTO implements Comparable<MyDTO> {
  private final String name;

The problem is:

I can have duplicated keys on the input:

    "KeyA": "ValueA",
    "KeyA": "ValueA.1",

Which then gets deduplicated by the native Java Map implementation – only the second key gets saved and I am okay with that. I found out Guava Multimap that would allow me to do it. This would allow me to accept a map with duplicates and let me execute the custom logic on the controller/service layer.

The problem is that I can’t find how to make spring boot parse this map in the controller without reformatting the request, I would like to keep it as it is. I was able to add the Object Mapper but I am failing to be able to receive this map from the request at the controller and use it.

Has anyone faced this issue before?


The problem is that I can't find how to make spring boot parse this map in the controller without reformatting the request

I’m not sure what you meant by this, but I assume that you are sending the request like this :

enter image description here

If you want to use com.google.common.collect.Multimap
there is no other way to send a request.

If you want to send a request in the form you mentioned in the question (withot [] brackets), as far as I can see, you have two options:

  1. Use org.apache.commons.collections4.MultiValuedMap with custom deserilizer;

Here is how your custom deserilizer should look like:

import com.example.demo.dto.MyDTO;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import org.apache.commons.collections4.MultiValuedMap;
import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;

import java.io.IOException;

class MultiValuedMapJsonDeerializer extends JsonDeserializer<MultiValuedMap> {

    public MultiValuedMap deserialize(JsonParser jp, DeserializationContext deserializationContext) throws IOException {
        MultiValuedMap<MyDTO, MyDTO> myDTOMyDTOMultiValuedMap = new ArrayListValuedHashMap<>();
        if (jp.getCurrentToken() != JsonToken.START_OBJECT) {
            throw new IOException("invalid start marker");

        while (jp.nextToken() != JsonToken.END_OBJECT) {
            String fieldname = jp.getCurrentName();
            String value = jp.getText();
            MyDTO key = new MyDTO(fieldname);
            MyDTO myDTO = new MyDTO(value);
            myDTOMyDTOMultiValuedMap.put(key, myDTO);

        return myDTOMyDTOMultiValuedMap;

    public Class<MultiValuedMap> handledType() {
        return MultiValuedMap.class;

Here is how endpoint shoud look like:

    public void createABC(@RequestBody final MultiValuedMap<MyDTO, MyDTO> map) {

When you hit this endpoint, you should see output like this:

{MyDTO(keyB)=[MyDTO(B)], MyDTO(keyC)=[MyDTO(C), MyDTO(D)], MyDTO(keyA)=[MyDTO(A)]}
  1. Use org.springframework.util.MultiValueMap

If you want to use this class, you shoud send your request body as x-www-form-urlencoded. Here is an example from Postman:

enter image description here

And finally, if you decide to use this option here is an example how controller method should look like:

    public void multiValueMap(@RequestBody MultiValueMap<MyDTO, MyDTO> multiValueMap) {

Using this approach, you should see output like this:

{KeyB=[b], KeyA=[a, c]}

Answered By – Nemanja

Answer Checked By – David Goodson (Easybugfix Volunteer)

Leave a Reply

(*) Required, Your email will not be published