Jackson 序列化Java List 对象

  本节讲解如何将Java List序列化成JSON,序列化和反序列化lists时,默认是不会保存类型信息的。下面演示两个例子,第一个example中,我们序列化一个包含Java List属性的对象;第二个例子中我们直接序列化Java List,这两个example中我们用Jackson Annotation在序列化时保留了类型信息。

Example 1: 序列化包含List的对象

  这个example转换Zoo类成json。 Zoo类包含动物园的name,所在city,和圈养的animals List。List中的数据类型是Animal,例如,list中包含的动物是抽象类Animal的子类。先看下序列化Zoo类时的结果。首先我们创建Zoo类实例,注意构造器的编码。当我们尝试从Json反序列化得到Zoo对象时,Jackson必须知道构建Zoo对象时应该用接收namecity属性的构造器方法。

 1 class Zoo {
 2     public String name;
 3     public String city;
 4  
 5      
 6     @JsonCreator
 7     public Zoo(@JsonProperty("name") String name,@JsonProperty("city") String city) {
 8         this.name = name;
 9         this.city = city;
10     }
11  
12     public List<Animal> animals = new ArrayList<Animal>();
13  
14     public List<Animal> addAnimal(Animal animal) {
15         animals.add(animal);
16         return animals;
17     }
18  
19 }

  Animal 是一个抽象类,用于扩展创建ElephantLion类。

 1 class Elephant extends Animal {
 2  
 3     @JsonCreator
 4     public Elephant(@JsonProperty("name") String name) {
 5         super.name = name;
 6     }
 7  
 8     @Override
 9     public String toString() {
10         return "Elephant : " + name;
11     }
12 }
13  
14 class Lion extends Animal {
15     @JsonCreator
16     public Lion(@JsonProperty("name") String name) {
17         this.name = name;
18     }
19  
20     @Override
21     public String toString() {
22         return "Lion: " + name;
23     }
24 }

  我们用ObjectMapper类执行序列化并将转换得到的json打印到控制台。当然你要可以用 mapper.writeValue(new File('zoo.json'), zoo)输出到zoo.json文件中。

 1 package com.test.jackson;
 2  
 3 import java.io.IOException;
 4 import java.util.ArrayList;
 5 import java.util.List;
 6  
 7 import com.fasterxml.jackson.core.JsonGenerationException;
 8 import com.fasterxml.jackson.databind.JsonMappingException;
 9 import com.fasterxml.jackson.databind.ObjectMapper;
10  
11 public class SerializeZoo {
12     public static void main(String[] args) throws JsonGenerationException, JsonMappingException, IOException {
13          Zoo zoo = new Zoo("London Zoo", "London");
14          Lion lion = new Lion("Simba");
15          Elephant elephant = new Elephant("Manny");
16          zoo.addAnimal(elephant).add(lion);
17          ObjectMapper mapper = new ObjectMapper();
18          mapper.writeValue(System.out, zoo);
19     }
20 }

Output

{"name":"London Zoo","city":"London","animals":[{"name":"Manny"},{"name":"Simba"}]}

  现在试试用得到的json字符串反序列化。

 1 import java.io.IOException;
 2  
 3 import com.fasterxml.jackson.core.JsonParseException;
 4 import com.fasterxml.jackson.databind.JsonMappingException;
 5 import com.fasterxml.jackson.databind.ObjectMapper;
 6  
 7 public class DeserializeZoo {
 8  
 9     public static void main(String[] args) throws JsonParseException, JsonMappingException, IOException {
10         String json = "{\"name\":\"London Zoo\",\"city\":\"London\"," + "\"animals\":[{\"name\":\"Manny\"},{\"name\":\"Simba\"}]}";
11         ObjectMapper mapper = new ObjectMapper();
12         mapper.readValue(json, Zoo.class);
13     }
14 }

Output

Can not construct instance of com.studytrails.json.jackson.Animal, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information

  我们得到一个error,这也是我们所期待的,因为序列化得到的json中没有保存List中对象的类型信息。想想如何解决,我们需要将对象的类型信息存储起来,我们只需做两件事。

  1. 我们需要告诉Jackson保留类信息
1 @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = As.PROPERTY, property = "@class")
  1. 告诉Jackson,Animal有子类Elephant和Lion类
1 @JsonSubTypes({ @Type(value = Lion.class, name = "lion"), @Type(value = Elephant.class, name = "elephant") })

Output

1 {"name":"London Zoo","city":"London",
2 "animals":[{"@class":"com.studytrails.json.jackson.Elephant","name":"Manny"},
3            {"@class":"com.studytrails.json.jackson.Lion","name":"Simba"}]}

  现在看起来好多了,你也可以用Zoo类来数据绑定json,将其反序列化成Zoo对象,一切都表现的很好,Zoo对象有一个动物列表。

Example 2: 直接序列化List

  在上面的example中,我们展示了如何序列化一个有List属性的类,这个例子中,我们将演示直接序列化List对象。继续沿用上面的类,看看当我们尝试直接序列化List对象时的结果,此时我们已经添加了同上个example的Jackson类型信息注解。

 1 public class SerializeAnimals {
 2     public static void main(String[] args) throws JsonGenerationException, JsonMappingException, IOException {
 3         List<animal> animals = new ArrayList<animal>();
 4         Lion lion = new Lion("Samba");
 5         Elephant elephant = new Elephant("Manny");
 6         animals.add(lion);
 7         animals.add(elephant);
 8         ObjectMapper mapper = new ObjectMapper();
 9  
10         mapper.writeValue(System.out, animals);
11     }
12 }

Output

[{"name":"Samba"},{"name":"Manny"}]

  尽然没有包含类型信息!为了在直接序列化List时保留类型信息,你需要以这样配置mapper:

1 mapper.writerWithType(new TypeReference<List
2         <Animal>>() {
3         }).writeValue(System.out, animals);

  现在就能输出期待的json:

1 [{"@class":"com.studytrails.json.jackson.Lion","name":"Samba"},
2 {"@class":"com.studytrails.json.jackson.Elephant","name":"Manny"}]