1.概述
本文主要展示如何使用Jackson 2将JSON数组反序列化为Java数组或集合。
要了解更多关于Jackson的用法,请移步Jackson系列文章
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最常用的功能之一,这些解决方案对于实现正确的、类型安全的映射至关重要。