序列化 之 Jackson(一)概要
Jackson 是 Java 生态中最流行、高性能的 JSON 处理库,由 FasterXML 维护。它不仅支持 JSON 与 Java 对象之间的双向转换(序列化/反序列化),还支持 XML、YAML、CSV 等多种数据格式。下面从核心原理和详细使用示例两方面深入解析。
一、Jackson 核心原理
1. 三大核心模块
| 模块 | Maven 坐标 | 功能 |
|---|---|---|
jackson-core |
com.fasterxml.jackson.core:jackson-core |
底层流式 API(JsonParser / JsonGenerator),提供高性能读写能力 |
jackson-databind |
com.fasterxml.jackson.core:jackson-databind |
高层数据绑定 API(ObjectMapper),实现 POJO 与 JSON 互转(最常用) |
jackson-annotations |
com.fasterxml.jackson.core:jackson-annotations |
注解支持(如 @JsonProperty, @JsonIgnore) |
✅ Spring Boot 默认集成 Jackson,无需额外引入依赖(除非版本冲突)。
2. 核心组件架构
[Java Object]
⇅ (通过 ObjectMapper)
[Token Stream] ←→ [JSON String]
⇅ (通过 JsonParser / JsonGenerator)
[Raw Bytes / Reader / Writer]
ObjectMapper:入口类,负责配置、序列化(writeValue)、反序列化(readValue)JsonFactory:创建底层JsonParser(读)和JsonGenerator(写)JsonParser:将 JSON 字符串解析为 Token 流(如START_OBJECT,FIELD_NAME,VALUE_STRING...)JsonGenerator:将 Token 流写入目标(String/Stream/File)
💡 性能关键:Jackson 使用 Streaming API + 反射/字节码生成 实现高效转换,避免中间 DOM 树构建(对比 Gson)。
3. 序列化/反序列化流程
序列化(Java → JSON)
ObjectMapper.writeValue()调用- 通过反射/ASM 获取对象字段/方法
- 按注解规则过滤/重命名字段
- 生成 Token 流 → 写入
JsonGenerator→ 输出 JSON
反序列化(JSON → Java)
ObjectMapper.readValue()调用JsonParser解析 JSON 为 Token 流- 根据目标类型构造对象(调用无参构造 or
@JsonCreator) - 按字段名匹配 Token 值,通过 setter/字段赋值
二、详细使用示例
示例 1:基础序列化与反序列化
// 定义 POJO
public class User {
public String name;
private int age;
// 必须有无参构造(或 @JsonCreator)
public User() {}
public User(String name, int age) {
this.name = name;
this.age = age;
}
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
}
// 使用 ObjectMapper
ObjectMapper mapper = new ObjectMapper();
// 序列化:Java → JSON
User user = new User("Alice", 30);
String json = mapper.writeValueAsString(user);
// 输出: {"name":"Alice","age":30}
// 反序列化:JSON → Java
User newUser = mapper.readValue(json, User.class);
⚠️ 注意:
- 字段需 public 或提供 getter/setter
- 必须有 无参构造函数(除非使用
@JsonCreator)
示例 2:常用注解控制行为
| 注解 | 作用 | 示例 |
|---|---|---|
@JsonProperty |
自定义 JSON 字段名 | @JsonProperty("user_name") String name; |
@JsonIgnore |
忽略字段 | @JsonIgnore String password; |
@JsonFormat |
格式化日期/数字 | @JsonFormat(pattern="yyyy-MM-dd") Date birth; |
@JsonInclude |
控制空值输出 | @JsonInclude(JsonInclude.Include.NON_NULL) |
@JsonCreator |
自定义反序列化构造 | 见下文 |
public class Product {
@JsonProperty("product_id")
private Long id;
@JsonInclude(JsonInclude.Include.NON_EMPTY)
private String description; // null 或 "" 不输出
@JsonFormat(pattern = "yyyy/MM/dd")
private Date createTime;
@JsonIgnore
private String secretKey;
// getter/setter...
}
示例 3:处理复杂场景
场景 1:反序列化时指定构造函数(@JsonCreator)
public class Point {
private final int x, y;
@JsonCreator
public Point(@JsonProperty("x") int x, @JsonProperty("y") int y) {
this.x = x;
this.y = y;
}
}
// JSON: {"x":10,"y":20} → 正确反序列化
场景 2:泛型反序列化(TypeReference)
List<User> users = mapper.readValue(jsonArray,
new TypeReference<List<User>>() {});
场景 3:忽略未知字段(防止反序列化失败)
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
场景 4:自定义序列化器(Serializer)
public class MoneySerializer extends JsonSerializer<BigDecimal> {
@Override
public void serialize(BigDecimal value, JsonGenerator gen, SerializerProvider serializers)
throws IOException {
gen.writeString("$" + value.setScale(2, RoundingMode.HALF_UP).toString());
}
}
// 使用
public class Order {
@JsonSerialize(using = MoneySerializer.class)
private BigDecimal amount;
}
示例 4:全局配置(Spring Boot 中常用)
@Configuration
public class JacksonConfig {
@Bean
@Primary
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
// 忽略未知字段
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// 空对象不抛异常
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
// 日期格式化
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
// 属性为 NULL 不序列化
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
return mapper;
}
}
✅ 在 Spring Boot 中,也可通过
application.yml配置:
spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
default-property-inclusion: non_null
deserialization:
fail-on-unknown-properties: false
三、高级特性
1. 混合注解(MixIn)
为无法修改的第三方类添加注解行为:
// 为 java.util.Date 添加格式化
public abstract class DateMixin {
@JsonFormat(pattern = "yyyy-MM-dd")
public abstract void setDate(Date d);
}
// 注册 MixIn
mapper.addMixIn(Date.class, DateMixin.class);
2. 树模型(JsonNode)
无需 POJO 直接操作 JSON:
JsonNode root = mapper.readTree(json);
String name = root.get("name").asText();
int age = root.get("age").asInt();
3. 流式处理(大文件)
避免内存溢出:
try (JsonParser parser = mapper.createParser(new File("huge.json"))) {
while (parser.nextToken() != null) {
// 逐个 Token 处理
}
}
四、常见问题与最佳实践
| 问题 | 解决方案 |
|---|---|
| 循环引用 StackOverflow | 使用 @JsonIdentityInfo 或 DTO 转换 |
| 日期格式混乱 | 全局配置 setDateFormat() 或字段级 @JsonFormat |
| 反序列化失败(UnknownProperty) | 关闭 FAIL_ON_UNKNOWN_PROPERTIES |
| 性能瓶颈 | 复用 ObjectMapper(线程安全!),避免重复创建 |
| 中文乱码 | 确保输出流编码为 UTF-8(Web 场景通常自动处理) |
✅ 重要:
ObjectMapper是 线程安全 的,应作为单例使用!
五、与其他库对比
| 特性 | Jackson | Gson | Fastjson |
|---|---|---|---|
| 性能 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐(但有安全风险) |
| 注解丰富度 | 极高 | 中等 | 中等 |
| Spring Boot 集成 | 默认 | 需替换 | 需替换 |
| 安全性 | 高 | 高 | 历史漏洞多 |
| 流式处理 | 支持 | 不支持 | 支持 |
📌 结论:在 Spring 生态中,Jackson 是首选。
总结
Jackson 的强大在于:
- 分层设计:Streaming(底层) + Databind(高层) + Annotations(灵活控制)
- 高性能:基于 Token 流 + 字节码优化
- 高度可定制:注解、自定义序列化器、MixIn、全局配置
掌握其核心原理和常用注解,能高效解决 99% 的 JSON 处理需求。在微服务、API 开发、配置解析等场景中不可或缺。
本文来自博客园,作者:蓝迷梦,转载请注明原文链接:https://www.cnblogs.com/hewei-blogs/articles/19513808

浙公网安备 33010602011771号