JSON、序列化和 Jackson 库简述

92 阅读4分钟

一、JSON 简述

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,是基于 JavaScript 的一个子集,但独立于语言,被广泛应用于前后端通信、配置文件、API 接口等领域。

JSON 在“传输 / 存储”层面是字符串,但在“语义”层面,它代表的是一种结构化数据格式。简单来说,传输时是字符串,使用时是数据结构。

这里是 JSON 的官方文档:传送门

1、核心特点

  1. 简洁易读:纯文本格式,人类和机器都容易读写。
  2. 语言无关:虽然源于 JavaScript,但几乎所有编程语言都支持解析和生成 JSON。
  3. 轻量级:相比 XML,JSON 结构更简单,冗余更少。
  4. 键值对结构:以键值对(Key-Value)存储数据,支持嵌套。

2、基本语法规则

六种数据类型,示例如下:

{
  "name": "张三",
  "age": 25,
  "isStudent": false,
  "skills": ["Python", "JavaScript"],
  "address": {
    "city": "北京",
    "zipcode": "100000"
  },
  "married": null
}

3、注意事项

  1. 键名必须用双引号(单引号无效)。
  2. JSON 标准(RFC 8259)本身不允许注释。
  3. 无日期类型:日期需转为字符串(如 "2025-07-29")。

4、第三方 Java 库

库名社区典型场景 & 优势最小示例
JacksonFasterXML企业级首选;与 Spring 无缝集成;支持流式、树模型、数据绑定;性能高、功能全。ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(obj);
FastjsonAlibaba速度极快;支持 JSONPath、自动类型转换;国内大量使用。String json = JSON.toJSONString(obj);
GsonGoogleAPI 极简;适合快速开发、Android;注解丰富;对泛型、嵌套对象支持好。Gson gson = new Gson();
String json = gson.toJson(obj);

二、什么是序列化?

序列化:把内存对象转换为字节序列(byte[]、文件、网络流)的过程。

反序列化:把字节序列还原为内存对象的过程。

序列化 / 反序列化的本质是对象和字节流的双向转换,让“活的”对象可以“死”着传输或存储。更广泛的来说,不限于字节流,任意可还原的中间表示也算序列化,如 JSON 文本。

三、Jackson 库

1、简介

序列化的方法有很多种,JDK 自带 Java 原生序列化(java.io.Serializable),零依赖,简单场景够用了。但我最常用的还是 Jackson 库。

Jackson 库是 Java 生态里的“JSON 事实标准”库,Spring Boot、Spring MVC 等框架都把它当作默认 JSON 引擎。因此,Spring Boot Starter Web 已间接包含 Jackson 库,无需额外引入依赖。

2、常用配置

实例 ObjectMapper 的可选配置项有很多种:

配置项描述说明配置枚举
日期不要时间戳Date / LocalDateTime 变成可读字符串,而不是 long 毫秒值SerializationFeature.WRITE_DATES_AS_TIMESTAMPS
JSON 美化输出生成带缩进、换行的易读格式SerializationFeature.INDENT_OUTPUT
空 Bean 不抛异常当类没有任何可见字段 / Getter 时,不再抛 InvalidDefinitionException,而是输出 {}SerializationFeature.FAIL_ON_EMPTY_BEANS
忽略未知属性当 JSON 里出现 Bean 没有的字段时,静默忽略,不抛 UnrecognizedPropertyExceptionDeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
允许注释支持 ///* */ 注释,解析器不再报错JsonParser.Feature.ALLOW_COMMENTS
允许单引号允许用单引号包裹字符串,兼容非标准 JSONJsonParser.Feature.ALLOW_SINGLE_QUOTES
允许尾部逗号允许最后一个元素后面多余逗号,兼容 JSON5 习惯JsonParser.Feature.ALLOW_TRAILING_COMMA
忽略 null过滤掉值为 null 的字段Include.NON_NULL
自定义日期格式让日期按指定格式(如 yyyy-MM-dd HH:mm:ss)输出 / 解析注册 JavaTimeModule

常用配置的示例如下:

import com.fasterxml.jackson.databind.ObjectMapper;

ObjectMapper mapper = new ObjectMapper()
        // JSON 美化输出
        .enable(SerializationFeature.INDENT_OUTPUT)
        // 忽略 null 值
        .setSerializationInclusion(JsonInclude.Include.NON_NULL);

3、常用序列化方法

Jackson 的 API 命名规律:

  • value:要被序列化的 Java 对象,与 JSON 字面量相对应。
  • write:把 Java 对象(value)往外写。
  • read:把外部数据(JSON 字面量)读进来变成 Java 对象。
  • tree:指一颗 JsonNode 对象树,一种可随机访问的内存树结构。ObjectNode 是 JsonNode 的可写子类,JsonNode 只读,ObjectNode 可改。
方向方法示例
对象 → JSON 字符串writeValueAsString(Object)String json = mapper.writeValueAsString(user);
对象 → 文件 / 网络流writeValue(File/OutputStream, Object)mapper.writeValue(new File("user.json"), user);
JSON → 对象readValue(String/File/InputStream, Class)User u = mapper.readValue(json, User.class);
JSON → 泛型集合readValue(..., TypeReference)List<User> list = mapper.readValue(json, new TypeReference<List<User>>(){});
JSON 字符串 → JsonNodereadTree(String)JsonNode root = mapper.readTree(json);
对象 → JsonNodevalueToTree(Object)JsonNode node = mapper.valueToTree(user);
JsonNode → 对象treeToValue(JsonNode, Class)User u = mapper.treeToValue(node, User.class);
全局配置configure(..., boolean) / setSerializationInclusion(...)见上文

4、内存类型的互转

convertValue:内存类型之间的相互转换,当需要 POJO ↔ Map / List ↔ 数组等内存互转,又不想走 JSON 字符串时,用它就对了。

// POJO → Map
User user = new User("Tom", 18);
Map<String, Object> map = mapper.convertValue(user, new TypeReference<>() {});
// map = {name=Tom, age=18}

// Map → POJO
User user2 = mapper.convertValue(map, User.class);

// List → 数组
List<String> list = List.of("a", "b", "c");
String[] array = mapper.convertValue(list, String[].class);
// array = ["a","b","c"]

四、碎碎念

  1. 其实这些经常会被统一写到静态工具类里,兼顾统一配置、减少开销、语义收敛等问题,比如 JsonSchemaUtils.java
  2. 这一篇本来是想讲如何使用 Jackson 的,结果来来回回研究序列化,越看越复杂,拖了好几天。上周刚开始时,我本来是想一天一更的,结果发现这个频率完全不现实。希望还是以自己满意的质量为主吧,坚持写下去。