skip to Main Content

I’ve been trying to deserialize an array of JSON objects for a while now, and all the answers on the internet are either deprecated or just don’t work for me.

The code below always returns a MismatchedInputException with the following message:

...MismatchedInputException: Root name ('builders')
does not match expected ('Builder[]') for type `[LModel.Attributes.Builder;`

Below is my code for my DTO:

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonRootName;

@JsonRootName("builders")
public class Builder {
    private  String id;
    private  String builder;

    @JsonProperty("id")
    public void setId(String id) {
        this.id = id;
    }

    @JsonProperty("name")
    public void setBuilder(String builder) {
        this.builder = builder;
    }

    public String getBuilder() {
        return builder;
    }

    public String getId(){
        return id;
    }
}

And here we have our deserializer:

var json = response.body();


mapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE);
var builders = mapper.readValue(json, Builder[].class);

And this is my JSON:

{
    "builders": [
        {
            "id": 1,
            "name": "Haley LLC"
        },
        {
            "id": 2,
            "name": "Stoltenberg, Mayert and Weimann"
        },
        {
            "id": 3,
            "name": "Ziemann Group"
        },
        {
            "id": 4,
            "name": "Monahan - Torp"
        },
        {
            "id": 5,
            "name": "Fritsch, Harber and Lemke"
        }
    ]
}

3

Answers


  1. Could you try with a wrapper class:

    public class Builder{
        public int id;
        public String name;
    }
    
    public class Root{
        public ArrayList<Builder> builders;
    }
    
    ObjectMapper mapper = new ObjectMapper();
    Root root = mapper.readValue(strJson, Root.class);
    
    Login or Signup to reply.
  2. Annotation @JsonRootName would work as expect if there would be a single object, not a JSON-array. In this case, we need a different approach.

    You can prepare an ObjectReader by specifying TypeReference of type List<Builder> using method ObjectMapper.readerFor( TypeReference ).

    And in order to unwrap this JSON-array, we can make use of the method ObjectReader.withRootName().

    Here’s how it might look like:

    String json = """
        {
            "builders": [
                {
                    "id": 1,
                    "name": "Haley LLC"
                },
                ... // other elements
            ]
        }
        """;
            
    ObjectMapper mapper = new ObjectMapper();
        
    ObjectReader objectReader = mapper
        .readerFor(new TypeReference<List<Builder>>() {})
        .withRootName("builders");
            
    List<Builder> builders = objectReader.readValue(json);
            
    builders.forEach(System.out::println);
    

    Output:

    Builder{id='1', builder='Haley LLC'}
    Builder{id='2', builder='Stoltenberg, Mayert and Weimann'}
    Builder{id='3', builder='Ziemann Group'}
    Builder{id='4', builder='Monahan - Torp'}
    Builder{id='5', builder='Fritsch, Harber and Lemke'}
    

    Note

    @JsonRootName on top of the Builder class is not needed in this case. You can remove it, if you have no another cases with a single Builder object being wrapped in the JSON.

    Also, applying deserialization feature UNWRAP_ROOT_VALUE is not required for this solution to work.

    Login or Signup to reply.
  3. You could just Deserialize to Map<String, List<Builder>> and then get by key "builders".

    Even semantically it’s not a bad representation because it is, after all, a JS Dictionary object with a list of Builders in it under the key "builders".

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search