本节讲解如何将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
对象时应该用接收name
和city
属性的构造器方法。
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
是一个抽象类,用于扩展创建Elephant
和Lion
类。
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中对象的类型信息。想想如何解决,我们需要将对象的类型信息存储起来,我们只需做两件事。
- 我们需要告诉Jackson保留类信息
1 @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = As.PROPERTY, property = "@class")
- 告诉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"}]