如果你最近刚把 Spring Boot 升级到 4.0,大概率已经遇到了一些“惊喜”——编译报错、导入失败、序列化行为异常,甚至运行时冒出从未见过的异常堆栈。

这一切的幕后推手,就是 Jackson 3

在很多人的印象里,Jackson 不过是个“处理 JSON 的工具库”。但说实话,它早已是 Java 生态中最基础、最重要的底层库之一。几乎所有的 Spring Boot 应用,都直接或间接地依赖它。

Jackson 的身影遍布各处:

  • REST API 的序列化与反序列化
  • Spring MVC 和 Spring WebFlux
  • Redis 对象存储
  • Kafka 消息转换
  • 配置文件解析
  • 日志框架
  • 微服务之间的通信

在 Jackson 2.x 服役了整整八年之后,3.0 版本的发布,堪称该项目历史上规模最大的一次架构升级。

这篇文章,我就带你梳理清楚:Jackson 3 到底改了什么?为什么说它意义重大?有哪些破坏性变更必须留意?以及,我们该如何平滑迁移。

为什么 Jackson 3 值得如此关注?

过去八年里,Jackson 2 的核心设计哲学是 向后兼容——尽可能不让已有代码出问题。

而 Jackson 3 彻底换了个思路,它的关键词变成了:

  • 拥抱现代 Java
  • 不可变 API
  • 更好的线程安全性
  • 更清晰的架构
  • 更强的类型安全
  • 更合理的默认配置
  • 更高的性能

说白了,就是不再背负历史包袱,围绕 Java 17 重新设计整个框架。

01
图片
Java 17 成为硬性门槛

最直观的变化:Jackson 3 要求 Java 17 或更高版本

版本
最低 JDK
Jackson 2.x
Java 8
Jackson 3.x
Java 17

这个升级让 Jackson 可以充分利用现代 Java 的新特性,比如:

  • 记录类(Records)
  • 密封类(Sealed Classes)
  • 模式匹配
  • 改进的反射 API
  • 更好的性能优化

如果你已经在用 Spring Boot 3 或 4,大概率已经跑在 Java 17 上了,这一步过渡会顺畅很多。0

2
图片
包名和 Maven 坐标全换了

升级后第一个遇到的编译错误,基本都来自 import。

Jackson 2 写法:

import com.fasterxml.jackson.databind.ObjectMapper;import com.fasterxml.jackson.core.JsonParser;

Jackson 3 写法:

import tools.jackson.databind.json.JsonMapper;import tools.jackson.core.JsonParser;

Maven 坐标也变了:

  • 之前:com.fasterxml.jackson
  • 之后:tools.jackson

有意思的是,注解的包名没有变,这意味着 Jackson 2 和 Jackson 3 可以在同一个应用中共存。这个设计为渐进式迁移留足了空间。0

3
图片
ObjectMapper 变成不可变的

这是架构层面最值得称道的改进。

Jackson 2 时代:

ObjectMapper mapper = new ObjectMapper();mapper.enable(SerializationFeature.INDENT_OUTPUT);mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

Mapper 可以在任意时刻被修改,在多线程环境下偶尔会引发一些难以捉摸的问题。

Jackson 3 的做法:

JsonMapper mapper = JsonMapper.builder()    .enable(SerializationFeature.INDENT_OUTPUT)    .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)    .build();

一旦调用了build(),配置就锁定了,对象变成不可变,线程安全性得到根本保障。

这种设计风格,也更符合现代 Java API 的主流审美。0

4
图片
每种格式都有自己的专属 Mapper

Jackson 2 允许你把不同格式混在一起用,Jackson 3 不再支持这种操作。

现在,每种数据格式都有独立的 Mapper:

JsonMapper jsonMapper = JsonMapper.builder().build();YAMLMapper yamlMapper = YAMLMapper.builder().build();XmlMapper xmlMapper = XmlMapper.builder().build();

这样职责更清晰,也能减少因配置混乱引发的低级错误。0

5
图片
异常体系全面翻新

Jackson 2 大量使用受检异常(checked exceptions):

try {    User user = mapper.readValue(json, User.class);} catch (JsonProcessingException e) {    // 处理异常}

Jackson 3 改成了非受检异常(unchecked):

User user = mapper.readValue(json, User.class);

如果解析失败,直接抛出

JacksonException

好处很明显:

  • API 更简洁
  • 样板代码大大减少
  • 和 Spring、Lombok 的风格更一致

另外,好几个异常类也改了名字,比如 JsonProcessingException → JacksonExceptionJsonParseException → StreamReadException 等。0

6
图片
默认配置变了,影响不小

这是最容易“踩坑”的地方——Jackson 3 改了好几个默认行为。

日期格式:从时间戳变为 ISO-8601

Jackson 2 默认把日期序列化成时间戳:

1721462400000

Jackson 3 默认输出 ISO-8601 字符串:

"2026-07-20T12:00:00Z"

更易读,也符合国际标准。如果你的前端还指望时间戳,可以手动恢复旧行为:

JsonMapper mapper = JsonMapper.builder()    .enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMP)    .build();

基本类型为 null 时不再悄悄转成默认值

假设你有这样一个类:

public class User {    private int age;}

Jackson 2 遇到 { “age”: null } 时,会静默地把

age 赋值为 0

Jackson 3 直接抛异常。

这其实是好事——防止数据被悄无声息地“篡改”。推荐的解决方式:

  • 使用 Integer 代替 int
  • 校验输入的 JSON
  • 实在需要的话,也可以关闭这个特性

月份处理更符合常理

Java 老版本里,Date API 中一月是 0 月,这经常把人搞晕。Jackson 3 在这方面更贴近现代日期 API,默认采用 1 为基础的月份处理。如果你的老代码里依赖了“0 月”逻辑,务必仔细检查相关流程。0

7
图片
性能提升实打实

Jackson 3 不只是变干净了,还更快了。

  • 懒加载 Bean 描述信息:元数据按需加载,减少临时对象,降低启动开销和 GC 压力。
  • RecyclerPool 优化:内部缓冲区池改为懒初始化,对于高频 JSON 处理的应用更省内存。
  • 减少字符串驻留(String Interning):默认不再对字段名做 intern,内存占用更低,高并发场景下扩展性更好。0
8
图片
依赖更少了

Jackson 2 为了支持现代 Java 特性,需要额外引入好几个模块:

  • jackson-module-parameter-names
  • jackson-datatype-jdk8
  • jackson-datatype-jsr310

Jackson 3 把这些能力直接整合进了 jackson-databind,依赖树一下子清爽了许多。

09
图片
破坏性变更速览
方面
Jackson 2
Jackson 3
最低 Java 版本
Java 8
Java 17
包名
com.fasterxml.jackson tools.jackson
核心 Mapper
ObjectMapper JsonMapper
配置方式
可变
不可变(Builder)
异常类型
受检异常
非受检异常
日期格式
时间戳
ISO-8601
基本类型为 null
允许,赋默认值
抛异常
ObjectCodec
存在
已移除
writeObject()
保留
改用 writePOJO()
getCurrentLocation()
保留
改用 currentLocation()

Jackson 3 的亮点,简单总结

  • 不可变、线程安全的 JsonMapper
  • 为现代 Java 量身打造
  • API 更清爽
  • 默认配置更合理
  • 安全性更强
  • 性能更好
  • 依赖管理更简单
  • 对 Records、Sealed Classes 支持更友好
  • 内存开销更低

对于新启动的 Spring Boot 项目,选 Jackson 3 几乎不需要犹豫。

迁移前需要注意什么?

别指望一键搞定,你需要评估并更新:

  • 所有 import 语句
  • Maven / Gradle 坐标
  • Mapper 创建方式(改用 Builder)
  • 异常处理逻辑
  • 序列化相关的单元测试
  • REST API 的契约测试

另外,Jackson 3.0 是首个 GA 版本,生产环境建议优先考虑 3.1.x,因为它是官方计划中的首个长期支持(LTS)版本。

推荐的迁移路径

第一步:先把项目升级到 Java 17。

第二步:升级到 Spring Boot 4。Spring Boot 4 在迁移期间同时兼容 Jackson 2 和 Jackson 3。

第三步:使用 OpenRewrite 自动辅助升级。

mvn rewrite:run \  -DactiveRecipes=org.openrewrite.java.jackson.UpgradeJackson_2_3

这个工具能帮你自动更新大部分 import 和 API 调用。

第四步:如果暂时不想改变太多行为,可以临时启用 Jackson 2 的兼容配置。Spring Boot 4 提供了一些开关,让你在过渡期内沿用旧默认值。

第五步:手动调整剩余代码,包括:

  • 替换 import
  • 改用 JsonMapper.builder()
  • 调整异常处理
  • 检查日期序列化结果
  • 验证 API 兼容性
  • 重新跑一遍集成测试
什么时候该升级?
场景
建议
全新 Spring Boot 4 项目
⭐⭐⭐⭐⭐ 强烈推荐
高并发应用
⭐⭐⭐⭐⭐ 强烈推荐
已经用 Java 17 的项目
⭐⭐⭐⭐⭐ 强烈推荐
现有 Spring Boot 迁移
⭐⭐ 谨慎规划
大型老项目
⭐⭐ 先评估依赖再做决定
图片
最后聊几句

Jackson 3 绝不仅仅是一次简单的版本号递增。

它通过拥抱不可变 API、Java 17、更合理的默认配置和实实在在的性能优化,让这个 Java 生态中最核心的库之一重新焕发了活力。

虽然升级过程中免不了要折腾一番——包名、异常、序列化行为都有变化——但长期来看,这些改动带来的收益是相当可观的。

如果你正在从头搭建 Spring Boot 4 项目,用 Jackson 3 是顺理成章的选择。对于已有的老项目,借助 OpenRewrite、充分的测试和临时的兼容配置,分阶段推进,也能把风险降到最低。

整个 Java 生态正在慢慢向 Jackson 3 靠拢。现在搞懂这些变化,等将来各种框架和库默认集成它时,你就不会手忙脚乱了。

希望这篇梳理对你有帮助。如果觉得有用,欢迎点个「在看」,转发给身边的小伙伴,你们的支持,是我持续输出的最大动力。

扫码领红包

微信赞赏支付宝扫码领红包

发表回复

后才能评论