I just released Module 10 in the Master Class of “REST with Spring”:

>> THE "REST WITH SPRING" CLASSES

1. Overview

This tutorial will show how to deserialize a JSON Array to a Java Array or Collection with Jackson 2.

If you want to dig deeper and learn other cool things you can do with the Jackson 2 – head on over to the main Jackson tutorial.

2. Unmarshall to Array

Jackson can easily deserialize to a Java Array:

@Test
public void givenJsonArray_whenDeserializingAsArray_thenCorrect() 
  throws JsonParseException, JsonMappingException, IOException {
 
    ObjectMapper mapper = new ObjectMapper();
    List<MyDto> listOfDtos = Lists.newArrayList(
      new MyDto("a", 1, true), new MyDto("bc", 3, false));
    String jsonArray = mapper.writeValueAsString(listOfDtos);
 
    // [{"stringValue":"a","intValue":1,"booleanValue":true},
    // {"stringValue":"bc","intValue":3,"booleanValue":false}]

    MyDto[] asArray = mapper.readValue(jsonArray, MyDto[].class);
    assertThat(asArray[0], instanceOf(MyDto.class));
}

3. Unmarshall to Collection

Reading the same JSON Array into a Java Collection is a bit more difficult – by default, Jackson will not be able to get the full generic type information and will instead create a collection of LinkedHashMap instances:

@Test
public void givenJsonArray_whenDeserializingAsListWithNoTypeInfo_thenNotCorrect() 
  throws JsonParseException, JsonMappingException, IOException {
 
    ObjectMapper mapper = new ObjectMapper();

    List<MyDto> listOfDtos = Lists.newArrayList(
      new MyDto("a", 1, true), new MyDto("bc", 3, false));
    String jsonArray = mapper.writeValueAsString(listOfDtos);

    List<MyDto> asList = mapper.readValue(jsonArray, List.class);
    assertThat((Object) asList.get(0), instanceOf(LinkedHashMap.class));
}

There are two ways to help Jackson understand the right type information – we can either use the TypeReference provided by the library for this very purpose:

@Test
public void givenJsonArray_whenDeserializingAsListWithTypeReferenceHelp_thenCorrect() 
  throws JsonParseException, JsonMappingException, IOException {
 
    ObjectMapper mapper = new ObjectMapper();

    List<MyDto> listOfDtos = Lists.newArrayList(
      new MyDto("a", 1, true), new MyDto("bc", 3, false));
    String jsonArray = mapper.writeValueAsString(listOfDtos);

    List<MyDto> asList = mapper.readValue(
      jsonArray, new TypeReference<List<MyDto>>() { });
    assertThat(asList.get(0), instanceOf(MyDto.class));
}

Or we can use the overloaded readValue method that accepts a JavaType:

@Test
publi void givenJsonArray_whenDeserializingAsListWithJavaTypeHelp_thenCorrect() 
  throws JsonParseException, JsonMappingException, IOException {
    ObjectMapper mapper = new ObjectMapper();

    List<MyDto> listOfDtos = Lists.newArrayList(
      new MyDto("a", 1, true), new MyDto("bc", 3, false));
    String jsonArray = mapper.writeValueAsString(listOfDtos);

    CollectionType javaType = mapper.getTypeFactory()
      .constructCollectionType(List.class, MyDto.class);
    List<MyDto> asList = mapper.readValue(jsonArray, javaType);
 
    assertThat(asList.get(0), instanceOf(MyDto.class));
}

One final note is that the MyDto class needs to have the no-args default constructor – if it doesn’t, Jackson will not be able to instantiate it:

com.fasterxml.jackson.databind.JsonMappingException: 
No suitable constructor found for type [simple type, class org.baeldung.jackson.ignore.MyDto]: 
can not instantiate from JSON object (need to add/enable type information?)

4. Conclusion

Mapping JSON arrays to java collections is one of the more common tasks that Jackson is used for, and these solutions are vital to getting to a correct, type-safe mapping.

The implementation of all these examples and code snippets can be found in our  GitHub project – this is a Maven-based project, so it should be easy to import and run as it is.

Go deeper into building a REST API with Spring:

>> CHECK OUT THE COURSE

  • Stephane

    Hi Eugen,

    Is it possible to turn this into a generic type ? So to have a readValue type agnostic.

    I’m trying this:
    protected List deserializeResources(final MvcResult mvcResult, Class clazz) throws Exception {
    return jacksonObjectMapper.readValue(mvcResult.getResponse().getContentAsString(), new TypeReference<List>(){});
    }

    But I’m getting the LinkedHashMap casting exception:
    java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.nsn.nitro.project.rest.resource.AdminModuleResource

    Whereas this works fine:
    protected List deserializeResources(final MvcResult mvcResult, Class clazz) throws Exception {
    return jacksonObjectMapper.readValue(mvcResult.getResponse().getContentAsString(), new TypeReference<List>(){});
    }

    Not easy to crack.

    Stephane

    • Stephane

      I just solved it 🙂

      protected List deserializeResources(final MvcResult mvcResult, Class clazz) throws Exception {
      final CollectionType javaType = jacksonObjectMapper.getTypeFactory().constructCollectionType(List.class, clazz);
      return jacksonObjectMapper.readValue(mvcResult.getResponse().getContentAsString(), javaType);
      }

      Thanks to you !

      • Looks good Stephane. If you need additional help, just add a quick test somewhere I can fork (github) and I’d be happy to take a look. Cheers,
        Eugen.

  • shaswat dasgupta

    Hi Eugen,

    Is there a way to attach a file in the JSON object? .I have a requirement where I need to generate a JSON request in the below format

    {
    “file”:”prices.xls”,
    “from” : “2015-01-01”,
    “to” : “2015-03-01”,
    }

    Please share your thoughts /ideas/code

    Thanks for any help

    • So, if you need to have the file name there, not the actual binary file – then your example JSON here looks good – you can certainly point to the file like that.
      If you need to actually have the binary content – I would not recommend doing that in the same JSON. Technically, is should be possible (though I’ve never tried it) – but there are much better ways to do that, such as have a separate upload option for the file and just refer to it in your JSON.
      Hope that helps. Cheers,
      Eugen.