Jackson详细介绍

Jackson 是一个能够将java对象序列化为JSON字符串,也能够将JSON字符串反序列化为java对象的框架。 

本文的所有内容都可以从 Java JSON Jackson Introduction 中找到,这里记录下来供自己以后参考,如果时间充足,建议阅读原文。

这是另一篇介绍自定义(反)序列化的文章 http://www.baeldung.com/jackson-custom-serialization

无论是序列化还是反序列化,Jackson都提供了三种方式:

1. JSON <--> Java Object 

2. JSON <--> JsonNode Tree(类似于XML的DOM树)

3. JSON <--> Json Stream (这是一个低层次的api,很强大,但是很繁琐)

Jackson提供了很多有用的注解来定制序列化,但是我们完全不用它的注解也可以完成绝大多数的工作。下面就从上面三种方式来一一介绍。

 

JSON <--> Java Object 

下面的Person类是一个普通的java POJO。它含有基本类型(包括String、Date)和一些集合类型,以及一个自定义的Address类型。

注意: 默认情况下,Jackson会处理所有public的属性和拥有getter方法的属性(反序列化需要setter)

复制代码
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Person {
    private String name;
    private int age;
    public Date birth;
    private Address address;
    private List<String> friends = new ArrayList<>();
    public Map<String, String> info = new HashMap<>();
    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public List<String> getFriends() {
        return friends;
    }
    public void setFriends(List<String> friends) {
        this.friends = friends;
    }
    public Address getAddress() {
        return address;
    }
    public void setAddress(Address address) {
        this.address = address;
    }
    
    //注意这个默认构造器,如果没有默认的构造器,应该有一个@JsonCreator修饰的构造器
    public Person(){}
    
    public Person(String name, int age, Address address, Date birth, String... friends){
        this.name = name;
        this.age = age;
        this.address = address;
        this.birth = birth;
        this.friends.addAll(Arrays.asList(friends));
    }
    
    @Override
    public String toString() {
        StringBuffer sb = new StringBuffer();
        sb.append("name: " + this.name + "\n");
        sb.append("age: " + this.age + "\n");
        sb.append("address: " + this.address + "\n");
        sb.append("birth: " + this.birth + "\n");
        this.friends.forEach(x -> sb.append("friend:"+ x + "\n"));
        
        return sb.toString();
    }
}
复制代码

 

复制代码
public class Address {
    public String homeAddress;
    public String workAddress;
    
    //跟Person一样,我们也必须提供一个无参的默认构造器
    public Address(){}
    
    public Address(String homeAddress, String workAddress) {
        this.homeAddress = homeAddress;
        this.workAddress = workAddress;
    }

    @Override
    public String toString() {
        return "home:" + this.homeAddress + "  " + "work:" + this.workAddress;
    }
}
复制代码

 

下面我们使用Jackson来(反)序列化 这个Person对象。

序列化:

复制代码
import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

public class SerializeTest {
    public static void main(String[] args) throws ParseException, JsonGenerationException, JsonMappingException, IOException {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        Date birth = format.parse("2010-10-10");
        
        Address address = new Address("New York", "Tokyo");
        Person person = new Person("zhangsan", 11, address, birth, "weiying", "caifang");
        person.info.put("height", "175cm");
        person.info.put("weight", "80kg");
        
        //使用ObjectMapper来序列化和反序列化
        ObjectMapper mapper = new ObjectMapper();
        
        //配置序列化的输出缩进
        mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
        //如果没有DateFormat,ObjectMapper将会把Date类型序列化为毫秒数 
        mapper.setDateFormat(format);
        //按照map的key的自然排序来产生序列化结果
        mapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);
        
        //序列化的过程就这一行代码,当然也可以选择输出到文件或其他流中
        mapper.writeValue(new File("person.json"), person);
    }
}
复制代码

 

反序列化:

复制代码
import java.io.File;
import java.io.IOException;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class DeserializeTest {
    public static void main(String[] args) throws JsonParseException, JsonMappingException, IOException {
        //反序列化同样从ObjectMapper开始
        ObjectMapper mapper = new ObjectMapper();
        
        //配置在反序列化过程中如果json字符串中存在无法匹配的属性不会失败
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        //上面的configure(xxx,false) 等同于disable(xxx),例如下面这行和上面作用是一样的。
        mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        
        //反序列化的过程也仅仅只有一行代码,同样可以从文件或其他流等输入中进行反序列化
        Person person = mapper.readValue(new File("person.json"), Person.class);
        
        System.out.println(person);
    }
}
复制代码

 在上面的例子中我们看到了Jackson最基本的(反)序列化过程,下面我们介绍一些用来定制(反)序列化的注解:

1.@JsonProperty - 在默认情况下,Jackson会处理所有public的属性和拥有getter(序列化)和setter(反序列化)的属性。但是我们可以使用 @JsonProperty来手动指定我们希望jackson处理的属性。于此同时,我们可以改变java对象映射到json中的属性名称(默认是相同的)。@JsonProperty相当于JAXB中的@XmlElement注解。

复制代码
import java.io.File;
import java.io.IOException;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

/**
 * 这个Dog类型没有任何public的属性和getter方法,但是我们使用@JsonProperty可以手动指定希望(反)序列化的属性,并能指定希望映射到json中的属性名称
 */
public class Dog {
    @JsonProperty("dog_name")
    private String name = "dahuang";
    private int age;
    
    @JsonProperty("dog_age")
    private int tellYourAge(){
        return this.age;
    }
    
    @JsonProperty("dog_age")
    private void giveMeAge(int age){
        this.age = age;
    }
    
    @Override
    public String toString() {
        return "dog(name: " + name + ";age: " + age + ")";
    }
    
    public static void main(String[] args) throws JsonGenerationException, JsonMappingException, IOException {
        ObjectMapper mapper = new ObjectMapper();
        //Jackson序列化空对象默认为失败
        mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        //配置ObjectMapper有两种方式,除了上面那种,下面这行代码是等价的。
        mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        //配置序列化格式
        mapper.enable(SerializationFeature.INDENT_OUTPUT);
        //上面这行代码同样等价于下面这行
        mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
        
        mapper.writeValue(new File("dog.json"), new Dog());
    
        Dog dog = mapper.readValue(new File("dog.json"), Dog.class);
        System.out.println(dog);
    }
}
复制代码

 

2.@JsonCreator - 在上面Person的例子中,我们除了定义了一个有参数的构造器外,还必须定义一个无参的默认构造器,这是因为在反序列化的过程中,Jackson不知道该向那个有参数的构造器中传递什么参数。 我们可以在构造器上使用 @JsonCreator,并在参数列表中使用@JsonProperty,这样在反序列化时Jackson就知道该如何使用这个构造器了,这个时候我们也就没必要定义那个无参的默认构造器了。

注意@JsonCreator仅仅在反序列化的过程中有用。

复制代码
import java.io.File;
import java.io.IOException;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class Dog {
    public String name;
    public int age;
    
    @Override
    public String toString() {
        return this.name + ":" + this.age;
    }
    //在反序列化的过程中,Jackson会将json串中的name属性传递给dog_name参数, 把json串中的age属性传递给dog_age参数。
    @JsonCreator
    public Dog(@JsonProperty("name") String dog_name, @JsonProperty("age") int dog_age){
        this.name = dog_name;
        this.age = dog_age;
    }
    
    public static void main(String[] args) throws JsonGenerationException, JsonMappingException, IOException {
        ObjectMapper mapper = new ObjectMapper();
        mapper.writeValue(new File("dog.json"), new Dog("dahuang", 11));
        
        Dog dog = mapper.readValue(new File("dog.json"), Dog.class);
        System.out.println(dog);
    }
}
复制代码

 

3.@JsonAnyGetter and @JsonAnySetter - 设想这样一种场景:除了java对象中明确指定的属性(包括使用@JsonProperty修饰指定的)外,我们希望能够随机的增加一些其他属性,让这些随机的属性也可以映射到json中去。这个时候我们就可以将这些不确定的属性放到一个map中去,并使用@JsonAnyGetter和@JsonAnySetter来修饰处理这个map的方法,然后Jackson就可以处理这些不确定的属性了。这两个属性相当于JAXB中的@XmlAnyElement和@XMLAnyAttribute。

复制代码
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class Dog {
    private Map<String, String> any = new HashMap<>();
    
    @JsonAnyGetter
    public Map<String, String> getAny(){
        return this.any;
    }
    
    @JsonAnySetter
    public void setAny(String key, String value){
        this.any.put(key, value);
    }

    public static void main(String[] args) throws JsonGenerationException, JsonMappingException, IOException {
        Dog dog = new Dog();
        //suck a big dog!!!
        dog.setAny("height", "175cm");
        dog.setAny("weight", "80kg");
        
        ObjectMapper mapper = new ObjectMapper();
        
        mapper.writerWithDefaultPrettyPrinter().writeValue(new File("dog.json"), dog);
        
        Dog dog2 = mapper.readValue(new File("dog.json"), Dog.class);
        dog2.getAny().forEach((x, y) -> System.out.println(x + "-->" + y));
    }
}
复制代码

 

4.@JsonIgnoreProperties and @JsonIgnore - 如果我们不希望Jackson处理java对象中public的属性或者拥有getter方法的属性,我们就可以使用这两个属性来忽略它们,相当于JAXB中@XmlTransient。

复制代码
import java.io.IOException;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

@JsonIgnoreProperties({"name", "age"})
public class Dog {
    public String name = "dahuang";
    public int age = 11;
    @JsonIgnore
    public String home = "CHN";

    public static void main(String[] args) throws JsonGenerationException, JsonMappingException, IOException {
        ObjectMapper mapper = new ObjectMapper();
        mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        //Dog的所有属性都已经被忽略了,所以此时应该序列化为一个空json串
        mapper.writeValue(System.out, new Dog());
    }

}
复制代码

 

除了使用@JsonIgnoreProperties and @JsonIgnore来忽略特定属性外,还可以像下面这样忽略空的属性:

复制代码
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

public class Dog {
    public String name = "";
    public List<String> info = new ArrayList<>();
    public List<String> info2 = null;
    
    public static void main(String[] args) throws JsonGenerationException, JsonMappingException, IOException {
        ObjectMapper mapper = new ObjectMapper();
        mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        
        //下面这行代码会忽略所有null或者空的属性,所以Dog此时依旧会被序列化为空JSON串
        mapper.setSerializationInclusion(Include.NON_EMPTY);
        mapper.writeValue(System.out, new Dog());
    }
}
复制代码

 

5.在序列化的过程中保存类型信息

下面定义了一个父类Animal和它的两个子类Dog和Cat,Person类有一个Animal类型的属性。

Animal:

复制代码
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

public class Animal {
    public String name;
    public int age;

    @JsonCreator
    public Animal(@JsonProperty("name") String name, @JsonProperty("age") int age){
        this.name = name;
        this.age = age;
    }
}
复制代码

 

Dog:

复制代码
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

public class Dog extends Animal{
    public String size;
    
    @JsonCreator
    public Dog(@JsonProperty("name") String name, @JsonProperty("age") int age, @JsonProperty("size") String size){
        super(name, age);
        this.size = size;
    }
}
复制代码

 

Cat:

复制代码
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

public class Cat extends Animal{
    public String color;
    
    @JsonCreator
    public Cat(@JsonProperty("name") String name, @JsonProperty("age") int age, @JsonProperty("color") String color){
        super(name, age);
        this.color = color;
    }
}
复制代码

 

Person:

public class Person {
    public Animal animal;
}

 

我们现在为Person的animal属性设置为Dog对象,然后序列化Person对象,之后再用得到的json串反序列化。

复制代码
import java.io.File;
import java.io.IOException;

import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class Test {
    public static void main(String[] args) throws JsonGenerationException, JsonMappingException, IOException {
        Person person = new Person();
        person.animal = new Dog("dahuang", 11, "big");
        
        ObjectMapper mapper = new ObjectMapper();
        mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        
        mapper.writeValue(new File("person.json"), person);
        
        Person p2 = mapper.readValue(new File("person.json"), Person.class);
        //在序列化的时候我们为Person对象animal属性赋予的是一个Dog对象,但是反序列化后得到的animal属性仅仅是一个animal对象。
        //实际上,如果Animal是一个抽象类型的话,此时就会报错了。
        System.out.println(p2.animal.getClass().getName());
    }
}
复制代码

 

在上面的例子序列化的结果是:

复制代码
{
  "animal" : {
    "name" : "dahuang",
    "age" : 11,
    "size" : "big"
  }
}
复制代码

 

在上面的结果中我们看到Jackson并没有将animal属性的具体类型信息保存下来,这样在反序列化的时候,Jackson就无法知道之前序列化时的真正类型,这就是上面反序列化后得到的是一个Animal而不是Dog的原因。

我们修改Animal如下:

复制代码
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeInfo.As;

@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = As.PROPERTY, property = "@class")
@JsonSubTypes({ @Type(value = Dog.class, name = "lion"), @Type(value = Cat.class, name = "elephant") })
public class Animal {
    public String name;
    public int age;

    @JsonCreator
    public Animal(@JsonProperty("name") String name, @JsonProperty("age") int age){
        this.name = name;
        this.age = age;
    }
}
复制代码

 

然后再次执行上面那段序列化和反序列化的代码,便可以得到Person的animal属性是一个Dog对象了。 序列化的json为:

复制代码
{
  "animal" : {
    "@class" : "com.massclouds.info.Dog",
    "name" : "dahuang",
    "age" : 11,
    "size" : "big"
  }
}
复制代码

 我们看到上面的json结果中多了一个@class的属性,它就代表了animal属性的类型信息。

 当我们直接序列化一个Animal的list或者以Animal为value的map时,上面的设置依旧无法将类型信息保存到json串中,下面我们演示如何直接(反)序列化包含Animal的list和map(注意此时Animal上的注解依旧要有)。

序列化:

复制代码
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

public class SerializeList {
    public static void main(String[] args) throws JsonGenerationException, JsonMappingException, IOException {
        List<Animal> animal_list = new ArrayList<>();
        animal_list.add(new Dog("dahuang", 11, "big"));
        animal_list.add(new Cat("miaomiao", 11, "grey"));
        
        Map<String, Animal> animal_map = new HashMap<>();
        animal_map.put("dog", new Dog("dahuagn", 11, "big"));
        animal_map.put("cat", new Cat("miaomiao", 11, "white"));
        
        ObjectMapper mapper = new ObjectMapper();
        mapper.enable(SerializationFeature.INDENT_OUTPUT);
        
        mapper.writerFor(new TypeReference<List<Animal>>(){}).writeValue(new File("list.json"), animal_list);
        
        mapper.writerFor(new TypeReference<Map<String, Animal>>(){}).writeValue(new File("map.json"), animal_map);
    }
}
复制代码

 

反序列化:

复制代码
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;

import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class SerializeList {
    public static void main(String[] args) throws JsonGenerationException, JsonMappingException, IOException {
        ObjectMapper mapper = new ObjectMapper();
        
        List<Animal> animal_list = mapper.readValue(new File("list.json"), new TypeReference<List<Animal>>(){});
        animal_list.forEach(animal -> System.out.println(animal.getClass().getName()));
        
        Map<String, Animal> animal_map = mapper.readValue(new File("map.json"), new TypeReference<Map<String, Animal>>(){});
        animal_map.forEach((key, value) -> System.out.println(key + " --> " + value.getClass().getName()));
    }
}
复制代码

 

上面需要注意的地方就是 由于Class对象中是不能携带泛型信息的,所以需要使用TypeReference。

 

6. Mix-in 

当我们使用的是第三方类库中的Java类型时,我们无法直接在类型上使用注解,此时我们可以使用Jackson提供的Mix-in功能。

我们有一个Dog类如下:

复制代码
public class Dog {
    public String name;
    private int age;
    
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    
    public Dog(String name, int age){
        this.name = name;
        this.age = age;
    }
}
复制代码

 

我们需要定义一个抽象类,如果我们希望在Dog类的什么地方使用注解,我们就在这个抽象类中定义一个相同的声明(属性或者方法),然后使用注解,例如我们希望在Dog中的getAge方法上使用@JsonProperty注解,那么我们就在这个抽象类中定义一个名称为getAge的抽象方法,然后再在这个抽象方法上使用@JsonProperty。下面是这个抽象类的实现:

复制代码
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

public abstract class DogMixin{
    @JsonProperty("dog_name")
    public String name;
    
    @JsonProperty("dog_age")
    public abstract int getAge();
    
    @JsonProperty("dog_age")
    public abstract void setAge(int age);
    
    @JsonCreator
    public DogMixin(@JsonProperty("dog_name") String name,@JsonProperty("dog_age") int age){
        //这里可以啥都没有。。。
    }
}
复制代码

 

然后在序列化的时候,像下面这样使用,就可以跟直接在Dog类中使用注解产生一样的效果了。

复制代码
import java.io.File;
import java.io.IOException;

import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class Test {
    public static void main(String[] args) throws JsonGenerationException, JsonMappingException, IOException {
        ObjectMapper mapper = new ObjectMapper();
        //注册我们使用的Mixin抽象类
        mapper.addMixIn(Dog.class, DogMixin.class);
        
        Dog dog = new Dog("dahuang", 11);
        mapper.writerWithDefaultPrettyPrinter().writeValue(new File("dog.json"), dog);
        
        Dog dog2 = mapper.readValue(new File("dog.json"), Dog.class);
        System.out.println(dog2.getAge() + " : " + dog2.name);
    }
}
复制代码

 

JSON <--> JsonNode Tree

就如同XML的DOM树一样,我们同样可以通过一颗json节点树来构建json,当然也可以将一个json字符串反序列化为一颗节点树。

Tree2JSON

复制代码
import java.io.FileOutputStream;
import java.io.IOException;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;

public class Tree2JSON {
    public static void main(String[] args) throws IOException {
        JsonFactory jsonFactory = new JsonFactory();
        JsonGenerator generator = jsonFactory.createGenerator(new FileOutputStream("tree.json"));
        
        ObjectMapper mapper = new ObjectMapper();
        
        JsonNodeFactory factory = new JsonNodeFactory(false);
        //生成一个根节点
        ObjectNode person = factory.objectNode();
        //普通属性直接添加即可
        person.put("name", "zhangsan");
        person.put("age",  11);
        
        //可以生成一个对象节点,然后把这个节点加入为根节点的子节点
        ObjectNode address = factory.objectNode();
        address.put("homeAddress", "New York");
        address.put("workAddress", "Tokyo");
        person.set("address", address);

        //同样可以生成一个Array节点, 然后把这个Array节点加入为根节点的子节点
        ArrayNode friends = factory.arrayNode();

        ObjectNode friend1 = factory.objectNode();
        friend1.put("name", "weiying");
        
        ObjectNode friend2 = factory.objectNode();
        friend2.put("name", "caifang");
        
        friends.add(friend1).add(friend2);
        person.set("friends", friends);
        
        mapper.writeTree(generator, person);
    }
}
复制代码

 

产生的json字符串为(我不知道在这种情况下序列化这个JSON,要是你知道请告诉我):

{"name":"zhangsan","age":11,"address":{"homeAddress":"New York","workAddress":"Tokyo"},"friends":[{"name":"weiying"},{"name":"caifang"}]}

 

下面将这个JSON串反序列化为一颗树,并遍历这颗树:

复制代码
import java.io.File;
import java.io.IOException;
import java.util.Iterator;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeType;

public class JSON2Tree {
    public static void main(String[] args) throws JsonProcessingException, IOException {
        ObjectMapper mapper = new ObjectMapper();
        // ObjectMapper读取json,返回根节点
        JsonNode root = mapper.readTree(new File("tree.json"));

        review(root);
    }

    // 递归遍历整棵树
    private static void review(JsonNode root) {
        if (root.getNodeType().equals(JsonNodeType.OBJECT)) {
            Iterator<String> fieldNames = root.fieldNames();
            while (fieldNames.hasNext()) {
                String fieldName = fieldNames.next();
                JsonNode node = root.get(fieldName);
                System.out.println(fieldName);
                review(node);
            }
        } else if (root.getNodeType().equals(JsonNodeType.ARRAY)) {
            ArrayNode array = (ArrayNode) root;
            Iterator<JsonNode> iter = array.iterator();
            iter.forEachRemaining(x -> review(x));
        } else {
            System.out.println(root);
        }
    }
}
复制代码

 

JSON <--> Json Stream 

Jackson提供了一种低层次的操作json的api,简单的说,就是Jackson读取json串后,会依次将json中的每个标志都产生相应的token,例如"{"表示对象的开始,那么Jackson 就产生一个表示对象开始的token。它很强大,但是很繁琐,不推荐使用。

复制代码
import java.io.File;
import java.io.IOException;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;

public class StramParser {
    public static void main(String[] args) throws JsonParseException, IOException {
        JsonFactory factory = new JsonFactory();
        JsonParser parser = factory.createParser(new File("person.json"));
        
        while(!parser.isClosed()){
            //这里仅仅简单的打印出token的类型和值(如果有的话)
            JsonToken token = parser.nextToken();
            System.out.println(token);
            System.out.println(parser.getText());
        }
    }
}
复制代码

 

复制代码
import java.io.IOException;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;

public class StreamGenerator {
    public static void main(String[] args) throws IOException {
        JsonFactory factory = new JsonFactory();
        JsonGenerator generator = factory.createGenerator(System.out);
 
        // start writing with {
        generator.writeStartObject();
        generator.writeFieldName("name");
        generator.writeString("zhangsan");
        generator.writeFieldName("address");
        // start an array
        generator.writeStartArray();
        generator.writeStartObject();
        generator.writeStringField("homeAddress", "New York");
        generator.writeEndObject();
        generator.writeStartObject();
        generator.writeStringField("workAddress", "Tokyo");
        generator.writeEndObject();

        generator.writeEndArray();
        generator.writeEndObject();
 
        generator.close();
    }
}
复制代码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值