Jackson

12/22/2021 JavaJSON

# 一:简介

# 1.1 json-lib

项目地址:http://json-lib.sourceforge.net/index.html (opens new window)

json-lib早期应用较广泛的json解析工具,依赖众多第三方包,包括:commons-beanutils.jar,commons-collections.jar,commons-lang.jar,commons-logging.jar,ezmorph.jar。
对于复杂类型的转换,存在缺陷。功能和性能上面都不能满足现在互联网化的需求。

# 1.2 Jackson

项目地址:https://github.com/FasterXML/jackson (opens new window)

用来序列化和反序列化 json 的 Java 的开源框架,依赖的jar包较少,简单易用并且性能也要相对高些。而且Jackson社区相对比较活跃,更新速度也比较快。
Jackson对于复杂类型的json转换bean会出现问题,一些集合Map,List的转换出现问题。
Jackson对于复杂类型的bean转换Json,转换的json格式不是标准的Json格式。
Spring MVC的默认json解析器便是Jackson。
Jackson 运行时占用内存比较低,性能比较好。
Jackson 有灵活的 API,可以很容易进行扩展和定制。
Jackson 的核心模块由三部分组成:

  1. jackson-core 核心包,提供基于 "流模式" 解析的相关 API,它包括 JsonPaser 和 JsonGenerator。Jackson 内部实现正是通过高性能的流模式 API 的 JsonGenerator 和 JsonParser 来生成和解析 json;
  2. jackson-annotations 注解包,提供标准注解功能;
  3. jackson-databind 数据绑定包,提供基于 "对象绑定" 解析的相关API(ObjectMapper)和"树模型"解析的相关API(JsonNode);基于"对象绑定"解析的API 和"树模型"解析的API 依赖基于"流模式"解析的API。
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.13.0</version>
</dependency>
1
2
3
4
5

jackson-databind 依赖 jackson-corejackson-annotations,当添加 jackson-databind 之后, jackson-corejackson-annotations 也随之添加到 Java 项目工程中。在添加相关依赖包之后,就可以使用 Jackson。

# 1.3 Gson

项目地址:https://github.com/google/gson (opens new window)

目前功能最全的Json解析神器,Gson当初是为因应Google公司内部需求而由Google自行研发而来。
Gson的应用主要为toJson与fromJson两个转换函数,无依赖,不需要例外额外的jar,能够直接跑在JDK上。
而在使用这种对象转换之前需先创建好对象的类型以及其成员才能成功的将JSON字符串成功转换成相对应的对象。
类里面只要有get和set方法,Gson完全可以将复杂类型的json到bean或bean到json的转换,是JSON解析的神器。
Gson在功能上面无可挑剔,但是性能上面比FastJson有所差距。

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.0</version>
</dependency>
1
2
3
4
5

# 1.4 FastJson

项目地址:https://github.com/alibaba/fastjson (opens new window)

Java语言编写的高性能的JSON处理器,无依赖,不需要例外额外的jar。
在复杂类型的Bean转换Json上会出现一些问题,可能会出现引用的类型,导致Json转换出错,需要制定引用。
FastJson采用独创的算法,将parse的速度提升到极致。

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.78</version>
</dependency>
1
2
3
4
5

fastjsonjackson 在把对象序列化成json字符串的时候,是通过反射遍历出该类中的所有getter方法;而 Gson 是通过反射遍历该类中的所有属性; 所以,在定义POJO中的布尔类型的变量时,不要使用isSuccess这种形式,而要直接使用success

# 二:快速入门

Jackson最常用的API 就是基于"对象绑定"的 ObjectMapper。它通过 writeValue 的系列方法将 Java 对象序列化为 JSON,并且可以存储成不同的格式。

  • writeValueAsString(Object value) 方法,将对象存储成字符串
  • writeValueAsBytes(Object value) 方法,将对象存储成字节数组
  • writeValue(File resultFile, Object value) 方法,将对象存储成文件

ObjectMapper通过 readValue 的系列方法从不同的数据源将JSON反序列化为Java对象。

  • readValue(String content, Class<T> valueType) 方法,将字符串反序列化为 Java 对象
  • readValue(byte[] src, Class<T> valueType) 方法,将字节数组反序列化为 Java 对象
  • readValue(File src, Class<T> valueType) 方法,将文件反序列化为 Java 对象

Person.class

@Data
@Accessors(chain = true)
public class Person {

    /**
     * 正常case
     */
    private String name;

    /**
     * 空对象case
     */
    private Integer age;

    /**
     * 日期转换case
     */
    private Date date;

    /**
     * 默认值case
     */
    private int height;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

JacksonTest.class

public class JacksonTest {

    @Test
    public void test1() throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        // 造数据
        Person person = new Person();
        person.setName("Tom").setAge(40).setDate(new Date());
        System.out.println("=================序列化=================");
        String jsonString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(person);
        System.out.println(jsonString);
        System.out.println("=================反序列化=================");
        Person deserializedPerson = mapper.readValue(jsonString, Person.class);
        // Person toString()
        System.out.println(deserializedPerson);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

结果

结果

ObjectMapper通过 writeValue 系列方法将java对象序列化为json,并将json存储成不同的格式,String(writeValueAsString),ByteArray(writeValueAsBytes),Writer,File,OutStream和DataOutput。

ObjectMapper通过 readValue 系列方法从不同的数据源(String,Byte Array,Reader,File,URL,InputStream)将json反序列化为java对象。

# 三:统一配置

在调用writeValue或调用readValue方法之前,往往需要设置ObjectMapper的相关配置信息。这些配置信息应用java对象的所有属性上。示例如下:

# 3.1 部分配置

// 在反序列化时,忽略在json中存在但Java对象不存在的属性
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// 在序列化时日期格式默认为yyyy-MM-dd'T'HH:mm:ss.SSSZ
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
// 在序列化时自定义时间日期格式
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
// 在序列化时忽略值为null的属性
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
// 在序列化时忽略值为默认值的属性
mapper.setDefaultPropertyInclusion(JsonInclude.Include.NON_DEFAULT);
1
2
3
4
5
6
7
8
9
10

更多配置信息可以查看Jackson的 DeserializationFeatureSerializationFeatureInclude

将上面的配置放入JacksonTest.class中进行测试

# 3.2 测试

JacksonTest.class

@Test
public void test2() throws IOException {
    ObjectMapper mapper = new ObjectMapper();
    //在反序列化时忽略在 json 中存在但 Java 对象不存在的属性
    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    //在序列化时日期格式默认为 yyyy-MM-dd'T'HH:mm:ss.SSSZ
    mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
    //在序列化时自定义时间日期格式
    mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
    //在序列化时忽略值为 null 的属性
    mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
    //在序列化时忽略值为默认值的属性
    mapper.setDefaultPropertyInclusion(JsonInclude.Include.NON_DEFAULT);
    // 造数据
    Person person = new Person();
    person.setName("Tom").setAge(40).setDate(new Date());
    System.out.println("=================序列化=================");
    String jsonString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(person);
    System.out.println(jsonString);
    System.out.println("=================反序列化=================");
    Person deserializedPerson = mapper.readValue(jsonString, Person.class);
    // Person toString()
    System.out.println(deserializedPerson);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

结果

结果

# 四:注解

Jackson根据它的默认方式序列化和反序列化java对象,若根据实际需要,灵活的调整它的默认方式,可以使用Jackson的注解。常用的注解及用法如下。

# 4.1 常用注解

注解 用法
@JsonProperty 用于属性,把属性的名称序列化时转换为另外一个名称。示例:
@JsonProperty("birth_date")
private Date birthDate;
@JsonIgnore 可用于属性、getter/setter、构造函数参数上,作用相同,都会对相应的字段产生影响。使相应字段不参与序列化和反序列化。
@JsonIgnoreProperties 该注解是类注解。该注解在Java类和JSON不完全匹配的时候使用。
@JsonFormat 用于属性或者方法,把属性的格式序列化时转换成指定的格式。示例:
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm")
public Date getBirthDate();
@JsonPropertyOrder 用于类,和@JsonProperty的index属性类似,指定属性在序列化时json中的顺序,示例:
@JsonPropertyOrder({"birth_Date","name"})
public class Person;
@JsonCreator 用于构造方法,和@JsonProperty配合使用,适用有参数的构造方法。示例:
@JsonCreator
public Person(@JsonProperty("name")String name) {…}
@JsonAnySetter 用于属性或者方法,设置未反序列化的属性名和值作为键值存储到map中
@JsonAnySetter
public void set(String key, Object value) {
map.put(key, value);
}
@JsonAnyGetter 用于方法,获取所有未序列化的属性
@JsonAnyGetter
public Map<String, Object> any() {
return map;
}
@JsonNaming 类注解。序列化的时候该注解可将驼峰命名的属性名转换为下划线分隔的小写字母命名方式。反序列化的时候可以将下划线分隔的小写字母转换为驼峰命名的字段名。示例:
@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
@JsonRootName 类注解。需开启mapper.enable(SerializationFeature.WRAP_ROOT_VALUE),用于序列化时输出带有根属性名称的JSON串,形式如{"root_name":{"id":1,"name":"zhangsan"}}。但不支持该JSON串反序列化。

# 4.2 测试

User.class

// 用于类,指定属性在序列化时json中的顺序
@JsonPropertyOrder({"date", "user_name"})
// 批量忽略属性,不进行序列化
@JsonIgnoreProperties(value = {"other"})
// 用于序列化与反序列化时的驼峰命名与小写字母命名转换
@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
@Data
public class User {

    @JsonIgnore
    private Map<String, Object> other = new HashMap<>();

    /**
     * 正常case
     */
    @JsonProperty("user_name")
    private String userName;

    /**
     * 空对象case
     */
    private Integer age;

    /**
     * 日期转换case
     */
    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
    private Date date;

    /**
     * 默认值case
     */
    private int height;

    // 反序列化执行构造方法
    @JsonCreator
    public User(@JsonProperty("user_name") String userName) {
        System.out.println("@JsonCreator 注解使得反序列化自动执行该构造方法 " + userName);
        // 反序列化需要手动赋值
        this.userName = userName;
    }

    @JsonAnySetter
    public void set(String key, Object value) {
        other.put(key, value);
    }

    @JsonAnyGetter
    public Map<String, Object> any() {
        return other;
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

JacksonTest.class

@Test
public void test3() throws IOException {
    ObjectMapper mapper = new ObjectMapper();
    // 造数据
    Map<String, Object> map = new HashMap<>();
    map.put("user_name", "Tom");
    map.put("date", "2020-07-26 19:28:44");
    map.put("age", 100);
    map.put("demoKey", "demoValue");
    System.out.println("=================Map 序列化=================");
    String jsonString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(map);
    System.out.println(jsonString);
    System.out.println("=================反序列化=================");
    User user = mapper.readValue(jsonString, User.class);
    System.out.println(user);
    System.out.println("=================序列化=================");
    jsonString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(user);
    System.out.println(jsonString);
    System.out.println("=================@JsonAnyGetter=================");
    System.out.println(user.any());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

结果

结果

# 五:日期处理

不同类型的日期类型,JackSon的处理方式也不同。

# 5.1 普通日期

对于日期类型为 java.util.Calendarjava.util.GregorianCalendarjava.sql.Datejava.util.Datejava.sql.Timestamp,若不指定格式,在json文件中将序列化为 long 类型的数据。显然这种默认格式,可读性差,转换格式是必要的。

Jackson 转换日期格式: * 注解方式,使用 @JsonFormat 注解指定日期格式 * ObjectMapper方式,调用ObjectMapper的方法 setDateFormat,将序列化为指定格式的string类型的数据。

# 5.2 Local 日期

对于日期类型为 java.time.LocalDate,java.time.LocalDateTime,还需要添加代码 mapper.registerModule(new JavaTimeModule()),同时添加相应的依赖 jar 包。

依赖

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.13.0</version>
</dependency>
1
2
3
4
5

对于Jackson 2.5以下版本,需要添加代码 mapper.registerModule(new JSR310Module ())

# 5.3 Joda日期

对于日期类型为 org.joda.time.DateTime,还需要添加代码 mapper.registerModule(new JodaModule()),同时添加相应的依赖jar包

<dependency> 
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-joda</artifactId> 
    <version>2.13.0</version>
</dependency>
1
2
3
4
5

# 5.4 测试

Student.class

@Data
@Accessors(chain = true)
public class Student {

    /**
     * 正常case
     */
    private String name;

    /**
     * 日期转换case
     */
    private LocalDateTime date;

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

JacksonTest.class

@Test
public void test4() throws IOException {
    ObjectMapper mapper = new ObjectMapper();
    // 必须添加对LocalDate的支持
    mapper.registerModule(javaTimeModule());
    // 造数据
    Student student = new Student();
    student.setName("Tom").setDate(LocalDateTime.now());
    System.out.println("=================序列化=================");
    String jsonString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(student);
    System.out.println(jsonString);
    System.out.println("=================反序列化=================");
    Student deserializedPerson = mapper.readValue(jsonString, Student.class);
    System.out.println(deserializedPerson);
}

private Module javaTimeModule() {
    JavaTimeModule module = new JavaTimeModule();
    String dateTimeFormat = "yyyy-MM-dd HH:mm:ss";
    String dateFormat = "yyyy-MM-dd";
    String timeFormat = "HH:mm:ss";
    // 序列化使用
    module.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(dateTimeFormat)));
    module.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(dateFormat)));
    module.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern((timeFormat))));
    // 反序列化使用
    module.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(dateTimeFormat)));
    module.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(dateFormat)));
    module.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(timeFormat)));
    return module;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

结果

结果

# 六:对象集合

Jackson对泛型反序列化也提供很好的支持

# 6.1 List

对于 List 类型,可以调用 constructCollectionType 方法来序列化,也可以构造 TypeReference 来序列化。

JacksonTest.class

@Test
public void test5() throws IOException {
    ObjectMapper mapper = new ObjectMapper();
    CollectionType javaType = mapper.getTypeFactory().constructCollectionType(List.class, Person.class);
    // 造数据
    List<Person> list = new ArrayList<>();
    for (int i = 0; i < 3; i++) {
    	Person person = new Person();
    	person.setName("Tom").setAge(new Random().nextInt(100)).setDate(new Date());
    	list.add(person);
    }
    System.out.println("=================序列化=================");
    String jsonInString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(list);
    System.out.println(jsonInString);
    System.out.println("=================反序列化:使用javaType=================");
    List<Person> personList = mapper.readValue(jsonInString, javaType);
    System.out.println(personList);
    System.out.println("=================反序列化:使用TypeReference=================");
    List<Person> personList2 = mapper.readValue(jsonInString, new TypeReference<List<Person>>() {
    });
    System.out.println(personList2);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

结果

结果

# 6.2 Map

对于 Map 类型,与List的实现方式相似。

JacksonTest.class

@Test
public void test6() throws IOException {
    ObjectMapper mapper = new ObjectMapper();
    //第二参数是map的key的类型,第三参数是map的value的类型
    MapType javaType = mapper.getTypeFactory().constructMapType(HashMap.class, String.class, Person.class);
    // 造数据
    Map<String, Person> map = new HashMap<>();
    for (int i = 0; i < 3; i++) {
    	Person person = new Person();
    	person.setName("Tom").setAge(new Random().nextInt(100)).setDate(new Date());
    	map.put("key" + i, person);
    }
    System.out.println("=================序列化=================");
    String jsonInString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(map);
    System.out.println(jsonInString);
    System.out.println("=================反序列化:使用javaType=================");
    Map<String, Person> personMap = mapper.readValue(jsonInString, javaType);
    System.out.println(personMap);
    System.out.println("=================反序列化:使用TypeReference=================");
    Map<String, Person> personMap2 = mapper.readValue(jsonInString, new TypeReference<Map<String, Person>>() {
    });
    System.out.println(personMap2);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

结果

结果

# 七:属性可视化

JackSon 默认不是所有的属性都可以被序列化和反序列化。默认的属性可视化的规则如下:

  • 若该属性修饰符是public,该属性可序列化和反序列化
  • 若属性的修饰符不是public,但是它的getter方法和setter方法是public,该属性可序列化和反序列化。因为getter方法用于序列化,而setter方法用于反序列化。
  • 若属性只有public的setter方法,而无public的getter方法,该属性只能用于反序列化。

若想更改默认的属性可视化的规则,需要调用 ObjectMapper 的方法 setVisibility。否则将会抛出 InvalidDefinitionException 异常。

如果反序列化的对象有带参的构造方法,它必须有一个空的默认构造方法,否则将会抛出 InvalidDefinitionException 一行

Teacher.class

@ToString
public class Teacher {

    public int age;

    protected String name;
}
1
2
3
4
5
6
7

JacksonTest.class

@Test
public void test7() throws IOException {
    ObjectMapper mapper = new ObjectMapper();
    // PropertyAccessor 支持的类型有 ALL,CREATOR,FIELD,GETTER,IS_GETTER,NONE,SETTER
    // Visibility 支持的类型有 ANY,DEFAULT,NON_PRIVATE,NONE,PROTECTED_AND_PUBLIC,PUBLIC_ONLY
    mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
    // 造数据
    Teacher teacher = new Teacher();
    teacher.name = "Tom";
    teacher.age = 40;
    System.out.println("=================序列化=================");
    String jsonString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(teacher);
    System.out.println(jsonString);
    System.out.println("=================反序列化=================");
    Teacher deserialized = mapper.readValue(jsonString, Teacher.class);
    System.out.println(deserialized);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

结果

结果

# 八:属性过滤

在将 Java 对象序列化为 json 时,有些属性需要过滤掉,不显示在json中,除了使用 @JsonIgnore 过滤单个属性或用 @JsonIgnoreProperties 过滤多个属性之外,Jackson还有通过代码控制的方式。

MyFilter.class

@JsonFilter("myFilter")
public class MyFilter {
}
1
2
3

JacksonTest.class

@Test
public void test8() throws JsonProcessingException {
    ObjectMapper mapper = new ObjectMapper();
    // 设置addMixIn
    mapper.addMixIn(Person.class, MyFilter.class);
    // 调用SimpleBeanPropertyFilter的serializeAllExcept方法
    SimpleBeanPropertyFilter newFilter = SimpleBeanPropertyFilter.serializeAllExcept("age");
    // 或重写SimpleBeanPropertyFilter的serializeAsField方法
    SimpleBeanPropertyFilter newFilter2 = new SimpleBeanPropertyFilter() {
    	@Override
    	public void serializeAsField(Object pojo, JsonGenerator jgen, SerializerProvider provider, PropertyWriter writer) throws Exception {
    		if (!writer.getName().equals("age")) {
    			writer.serializeAsField(pojo, jgen, provider);
    		}
    	}
    };
    //设置 FilterProvider
    FilterProvider filterProvider = new SimpleFilterProvider().addFilter("myFilter", newFilter);
    // 造数据
    Person person = new Person();
    person.setName("Tom");
    // 该属性将被忽略
    person.setAge(40);
    person.setDate(new Date());
    // 序列化
    String jsonString = mapper.setFilterProvider(filterProvider).writeValueAsString(person);
    System.out.println("=================序列化=================");
    System.out.println(jsonString);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

结果

结果

# 九:自定义序列化类

当Jackson默认序列化和反序列化的类不能满足实际需要,可以自定义新的序列化和反序列化的类。

自定义序列化类:自定义的序列化类需要直接或间接继承 StdSerializerJsonSerializer,同时需要利用 JsonGenerator 生成json,重写方法 serialize,示例如下:

CustomSerializer.class

public class CustomSerializer extends StdSerializer<Person> {

    protected CustomSerializer() {
        super(Person.class);
    }

    @Override
    public void serialize(Person person, JsonGenerator jgen, SerializerProvider provider) throws IOException {
        jgen.writeStartObject();
        jgen.writeNumberField("age", person.getAge());
        jgen.writeStringField("name", person.getName());
        jgen.writeStringField("msg", "已被自定义序列化");
        jgen.writeEndObject();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

JsonGenerator 有多种write方法以支持生成复杂的类型的json,比如 writeArray,writeTree等。若想单独创建JsonGenerator,可以通过 JsonFactory()createGenerator

自定义反序列化类:自定义的反序列化类需要直接或间接继承 StdDeserializerStdDeserializer,同时需要利用 JsonParser 读取 json,重写方法 deserialize,示例如下:

CustomDeserializer.class

public class CustomDeserializer extends StdDeserializer<Person> {

    protected CustomDeserializer() {
        super(Person.class);
    }

    @Override
    public Person deserialize(JsonParser jp, DeserializationContext deserializationContext) throws IOException {
        JsonNode node = jp.getCodec().readTree(jp);
        Person person = new Person();
        int age = (Integer) (node.get("age")).numberValue();
        String name = node.get("name").asText();
        person.setAge(age);
        person.setName(name);
        return person;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

JsonParser提供很多方法来读取json信息,如isClosed(),nextToken(),getValueAsString() 等。若想单独创建JsonParser,可以通过 JsonFactory()createParser

定义好自定义序列化类和自定义反序列化类,若想在程序中调用它们,还需要注册到ObjectMapper的Module,示例如下:

JacksonTest.class

@Test
public void test9() throws IOException {
    ObjectMapper mapper = new ObjectMapper();
    // 生成 module
    SimpleModule module = new SimpleModule("myModule");
    module.addSerializer(new CustomSerializer());
    module.addDeserializer(Person.class, new CustomDeserializer());
    // 注册 module
    mapper.registerModule(module);
    // 造数据
    Person person = new Person();
    person.setName("Tom");
    person.setAge(40);
    person.setDate(new Date());
    System.out.println("=================序列化=================");
    String jsonString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(person);
    System.out.println(jsonString);
    System.out.println("=================反序列化=================");
    Person deserializedPerson = mapper.readValue(jsonString, Person.class);
    System.out.println(deserializedPerson);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

结果

结果

或者也可通过注解方式加在java对象的属性,方法或类上面来调用它们:

  • @JsonSerialize(using = CustomSerializer.class)
  • @JsonDeserialize(using = CustomDeserializer.class)

# 十:树模型处理

Jackson也提供了树模型(tree model)来生成和解析json。若想修改或访问json部分属性,树模型是不错的选择。树模型由JsonNode节点组成。程序中常常使用ObjectNode,ObjectNode继承于JsonNode,示例如下:

JacksonTest.class

@Test
public void test10() throws IOException {
    ObjectMapper mapper = new ObjectMapper();
    //构建 ObjectNode
    ObjectNode personNode = mapper.createObjectNode();
    //添加/更改属性
    personNode.put("name", "Tom");
    personNode.put("age", 40);
    ObjectNode addressNode = mapper.createObjectNode();
    addressNode.put("zip", "000000");
    addressNode.put("street", "Road NanJing");
    //设置子节点
    personNode.set("address", addressNode);
    System.out.println("构建 ObjectNode:\n" + personNode);
    //通过 path 查找节点
    JsonNode searchNode = personNode.path("name");
    System.out.println("查找子节点 name:\n" + searchNode.asText());
    //删除属性
    ((ObjectNode) personNode).remove("address");
    System.out.println("删除后的 ObjectNode:\n" + personNode);
    //读取 json
    JsonNode rootNode = mapper.readTree(personNode.toString());
    System.out.println("Json 转 JsonNode:\n" + rootNode);
    //JsonNode 转换成 java 对象
    Person person = mapper.treeToValue(personNode, Person.class);
    System.out.println("JsonNode 转对象:\n" + person);
    //java 对象转换成 JsonNode
    JsonNode node = mapper.valueToTree(person);
    System.out.println("对象转 JsonNode:\n" + node);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

结果

结果

# 十一:补充

//序列化BigDecimal时之间输出原始数字还是科学计数, 默认false, 即是否以toPlainString()科学计数方式来输出
mapper.enable(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN);
//允许将JSON空字符串强制转换为null对象值
mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
//允许单个数值当做数组处理
mapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
//禁止重复键, 抛出异常
mapper.enable(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY);
//禁止使用int代表Enum的order()來反序列化Enum, 抛出异常
mapper.enable(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS);
//有属性不能映射的时候不报错
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
//使用null表示集合类型字段是时不抛异常
mapper.disable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES);
//对象为空时不抛异常
mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
//允许在JSON中使用c/c++风格注释
mapper.enable(JsonParser.Feature.ALLOW_COMMENTS);
//强制转义非ascii字符
mapper.disable(JsonGenerator.Feature.ESCAPE_NON_ASCII);
//允许未知字段
mapper.enable(JsonGenerator.Feature.IGNORE_UNKNOWN);
//在JSON中允许未引用的字段名
mapper.enable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES);
//时间格式
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
//识别单引号
mapper.enable(JsonParser.Feature.ALLOW_SINGLE_QUOTES);
//识别特殊字符
mapper.enable(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS);
//识别Java8时间
mapper.registerModule(new ParameterNamesModule());
mapper.registerModule(new Jdk8Module());
mapper.registerModule(new JavaTimeModule());
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

特别说明

new ParameterNamesModule() 需要使用到 jackson-module-parameter-names jar包

<dependency>
    <groupId>com.fasterxml.jackson.module</groupId>
    <artifactId>jackson-module-parameter-names</artifactId>
    <version>2.13.0</version>
</dependency>
1
2
3
4
5

new Jdk8Module() 需要使用到 jackson-datatype-jdk8 jar包

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jdk8</artifactId>
    <version>2.13.0</version>
</dependency>
1
2
3
4
5

# 十二:参考文献

最后更新: 12/24/2021, 9:20:53 AM