1. 概述

本教程将展示如何使用Jackson 2将JSON数组反序列化为Java数组或集合。

如果你希望深入了解Jackson 2的其他酷炫功能,可以访问Jackson 2教程

2. 反序列化到数组

Jackson可以轻松地将JSON反序列化为Java数组:

@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. 反序列化到集合

将相同的JSON数组读入Java集合稍微困难一些 - 默认情况下,Jackson无法获取完整的泛型类型信息,而是会创建一个LinkedHashMap实例的集合:

@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));
}

有两种方式可以帮助Jackson理解正确的类型信息:我们可以使用库提供的专门为此目的的TypeReference

@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));
}

或者使用接受JavaType的重载readValue方法:

@Test
public 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));
}

最后一点是,MyDto类需要有一个无参数的默认构造函数 - 如果没有,Jackson将无法实例化它

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?)

另一种选择是使用@JsonCreator注解来调整反序列化的构造函数。

4. 总结

将JSON数组映射到Java集合是Jackson常用于的任务之一,这些解决方案对于实现正确、类型安全的映射至关重要。

所有示例和代码片段的实现可以在我们的GitHub项目中找到 - 这是一个基于Maven的项目,导入并运行非常方便。