【Jackson】 - 反序列化为数组或集合

Jackson –反序列化为数组或集合

1.概述

本文主要展示如何使用Jackson 2将JSON数组反序列化为Java数组或集合

https://www.wdbyte.com/tool/jackson.html#json-介绍

2.反序列化为数组

Jackson很容易将JSON字符串反序列化为Java数组:

    @Test //json字符串转换为数组  
    public void  jsonStringToArray() throws JsonProcessingException {  
        //创建ObjectMapper对象  
        ObjectMapper mapper\=new ObjectMapper();  
        String json = "[\"C\",\"C++\",\"Java\",\"Python\",\"Golang\",\"JavaScript\"]";  
        String[] array = mapper.readValue(json, String[].class);  
        for (String str:array) {  
            System.out.println(str);  
        }  
    }  
  
    @Test //json数组反序列化为数组对象  
    public final void jsonStringToArrayObject() throws JsonProcessingException {  
         ObjectMapper mapper = new ObjectMapper();  
         List<MyDto> listOfDtos = Lists.newArrayList(new MyDto("a", 1, true),  
                                                     new MyDto("bc", 3, false));  
         String jsonArray = mapper.writeValueAsString(listOfDtos);  
         System.out.println(jsonArray);  
         MyDto[] asArray = mapper.readValue(jsonArray, MyDto[].class);  
         assertThat(asArray[0], instanceOf(MyDto.class));  
         System.out.println(asArray.length);  
         System.out.println(asArray[0]);  
    }

3.反序列化为集合

将相同的JSON数组反序列化为Java集合要复杂一些。默认情况下,Jackson无法获取完整的泛型类型信息,而是将JSON数组反序列化为一个Linked _HashMap_实例的集合。转换不会出现错误,但是获取具体数据时会抛出异常。

    @Test //json数组反序列化为List对象  
    public  void jsonStringToListObject() throws JsonProcessingException {  
         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);  
         System.out.println(asList.get(0));  
         //获取对象具体值时抛出异常  
         System.out.println(asList.get(0).getStringValue());  
    }

抛出异常如下:

java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.wxbsusht.jackson.tocollection.MyDto

有两种方法可以使Jackson理解正确的类型信息 。第一种时Jackson库提供的_TypeReference_:

    @Test  
    public void jsonStringToListObjectByTypeReference() throws JsonProcessingException {  
         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));  
         System.out.println(asList.get(0));  
         //获取正确结果  
         System.out.println(asList.get(0).getStringValue());  
    }

另外一种是使用重载的readValue方法来接受JavaType:

    @Test  
    public  void jsonStringToListObjectByCollectionType() throws JsonProcessingException {  
         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));  
         System.out.println(asList.get(0));  
         //获取正确结果  
         System.out.println(asList.get(0).getStringValue());  
    }

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

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of \`com.wxbsusht.jackson.tocollection.MyDto\` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate\- or property\-based Creator)

对于带有泛型的对象反序列化时,可以使用TypeReference

public class Pager<T\> {  
    private Integer totalCount;  
    private Integer currentPage;  
    private List<T\> datas;  
 }

其中User类需要有一个无参数的默认构造函数——如果没有,则Jackson将无法实例化它

@Test  
public  void jsonStringToListObjectByGeneric() throws JsonProcessingException {  
    ObjectMapper mapper \= new ObjectMapper();  
    List<User\> userList \= Lists.newArrayList(new User("jack", 25),  
            new User("tom", 3));  
    Pager<User\> pager\=new Pager<>();  
    pager.setCurrentPage(2);  
    pager.setTotalCount(200);  
    pager.setDatas(userList);  
    String jsonString \= mapper.writeValueAsString(pager);  
    System.out.println(jsonString);  
  
    Pager<User\> userPager \= mapper.readValue(jsonString, new TypeReference< Pager<User\>>() {});  
  
    System.out.println(userPager);  
    //获取正确结果  
    // Pager{totalCount=200, currentPage=2, datas=\[User{name='jack', age=25}, User{name='tom', age=3}\]}  
}

4. 结论

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

posted @ 2023-01-30 16:37  明小子@  阅读(11)  评论(0)    收藏  举报