springboot 4 升级 Jackson 3,避免这 5 个坑
如果你最近刚把 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 2 的核心设计哲学是 向后兼容——尽可能不让已有代码出问题。
而 Jackson 3 彻底换了个思路,它的关键词变成了:
拥抱现代 Java
不可变 API
更好的线程安全性
更清晰的架构
更强的类型安全
更合理的默认配置
更高的性能
说白了,就是不再背负历史包袱,围绕 Java 17 重新设计整个框架。
最直观的变化:Jackson 3 要求 Java 17 或更高版本。
这个升级让 Jackson 可以充分利用现代 Java 的新特性,比如:
记录类(Records)
密封类(Sealed Classes)
模式匹配
改进的反射 API
更好的性能优化
如果你已经在用 Spring Boot 3 或 4,大概率已经跑在 Java 17 上了,这一步过渡会顺畅很多。0
升级后第一个遇到的编译错误,基本都来自 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
这是架构层面最值得称道的改进。
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
Jackson 2 允许你把不同格式混在一起用,Jackson 3 不再支持这种操作。
现在,每种数据格式都有独立的 Mapper:
JsonMapper jsonMapper = JsonMapper.builder().build();YAMLMapper yamlMapper = YAMLMapper.builder().build();XmlMapper xmlMapper = XmlMapper.builder().build();
这样职责更清晰,也能减少因配置混乱引发的低级错误。0
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 → JacksonException,JsonParseException → StreamReadException 等。0
这是最容易“踩坑”的地方——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
Jackson 3 不只是变干净了,还更快了。
懒加载 Bean 描述信息:元数据按需加载,减少临时对象,降低启动开销和 GC 压力。
RecyclerPool 优化:内部缓冲区池改为懒初始化,对于高频 JSON 处理的应用更省内存。
减少字符串驻留(String Interning):默认不再对字段名做 intern,内存占用更低,高并发场景下扩展性更好。0
Jackson 2 为了支持现代 Java 特性,需要额外引入好几个模块:
jackson-module-parameter-namesjackson-datatype-jdk8jackson-datatype-jsr310
Jackson 3 把这些能力直接整合进了 jackson-databind,依赖树一下子清爽了许多。
com.fasterxml.jackson | tools.jackson | |
ObjectMapper | JsonMapper | |
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 兼容性
重新跑一遍集成测试
最后聊几句
Jackson 3 绝不仅仅是一次简单的版本号递增。
它通过拥抱不可变 API、Java 17、更合理的默认配置和实实在在的性能优化,让这个 Java 生态中最核心的库之一重新焕发了活力。
虽然升级过程中免不了要折腾一番——包名、异常、序列化行为都有变化——但长期来看,这些改动带来的收益是相当可观的。
如果你正在从头搭建 Spring Boot 4 项目,用 Jackson 3 是顺理成章的选择。对于已有的老项目,借助 OpenRewrite、充分的测试和临时的兼容配置,分阶段推进,也能把风险降到最低。
整个 Java 生态正在慢慢向 Jackson 3 靠拢。现在搞懂这些变化,等将来各种框架和库默认集成它时,你就不会手忙脚乱了。
希望这篇梳理对你有帮助。如果觉得有用,欢迎点个「在看」,转发给身边的小伙伴,你们的支持,是我持续输出的最大动力。
