升级 Spring Boot 到 4.0 版本后,默认集成的 JSON 处理库 Jackson 也迎来了从 2.x 到 3.x 的重大升级。这次升级远不止是版本号的简单迭代,其中包含了包名重组、API变更等关键性突破,开发者若不了解这些变化,在迁移过程中很可能“踩坑”。本文将详细解析 Spring Boot 4.0 全面拥抱 Jackson 3 的核心变化与迁移注意事项。
为什么 Jackson 2 和 3 会同时出现?
升级 Spring Boot 4 后,如果你执行 mvn dependency:tree 或者 ./gradlew dependencies 命令查看依赖树,可能会发现一个有趣的现象:
spring-boot-starter-jackson (4.x)
├── tools.jackson.core:jackson-core:3.x ← Jackson 核心实现(新包)
└── com.fasterxml.jackson.annotation:jackson-annotations:2.x ← Jackson 注解(旧包)

很多开发者的第一反应是“依赖冲突了”。其实不然,这是 Jackson 开发团队一次非常工程化且务实的设计决策。
他们清醒地认识到,整个 Java 生态中数以万计的第三方库不可能在一夜之间全部修改包名引用。因此,他们采取了“核心实现迁移至新包,注解层沿用旧包”的渐进式迁移策略。这意味着你项目中常用的 @JsonProperty、@JsonIgnore 等注解完全无需改动。这种最大限度降低迁移成本的思路,非常值得我们在进行系统架构演进时学习。
Jackson 3 的四大破坏性变更
Spring Boot 4 默认升级到 Jackson 3 后,开发者需要重点关注以下四个主要变化。如果不提前了解并适配,线上服务很可能出现意想不到的 Bug。
这是最直观的改动。所有核心实现类的包名都发生了迁移:
// Jackson 2 (旧)
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
// Jackson 3 (新)
import tools.jackson.core.JacksonException;
import tools.jackson.core.type.TypeReference;
import tools.jackson.databind.ObjectMapper;
需要特别注意:只有核心 API 类更换了包名,而所有的注解类依然保留在旧的 com.fasterxml.jackson.annotation 包下。切勿在项目中全局替换所有的 com.fasterxml 字符串,否则你的注解导入将全部报错。
2. ObjectMapper 退出舞台,JsonMapper 强制登场
在 Jackson 2 时代,ObjectMapper 实例是可变的(Mutable),开发者可以在运行时修改其配置,但这在多线程环境下潜藏着风险。
Jackson 3 强力推行 Builder(建造者)模式与不可变(Immutable)对象 的设计理念:
// Jackson 3 推荐写法
JsonMapper mapper = JsonMapper.builder()
.enable(SerializationFeature.INDENT_OUTPUT)
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
.build();
一旦通过 build() 方法构建出 JsonMapper 实例,其所有配置将被“锁定”,无法再被修改。这种设计使得 JsonMapper 实例天然是线程安全的。如果你尝试直接 new ObjectMapper(),只能得到一个使用默认配置的实例;想要进行任何自定义配置?对不起,请务必使用 Builder 模式。
3. 默认日期序列化格式更改
这是最容易导致前后端联调失败或测试用例报错的变化。Jackson 3 彻底改变了默认的日期输出格式:
| 维度 |
Jackson 2 默认行为 |
Jackson 3 默认行为 |
| 输出格式 |
时间戳 (Long) |
ISO-8601 字符串 |
| 示例结果 |
{"now": 1767588151648} |
{"now": "2026-01-05T02:02:31Z"} |
避坑提醒:如果你的前端代码写死了按照时间戳(Long 类型)来解析日期字段,或者后端测试用例中存在对时间戳值的硬编码断言(Assert),升级 Jackson 3 后这些逻辑会全线崩溃。
【临时过渡方案】:如果你希望立即升级 Spring Boot 4.0 但暂时保持原有的日期序列化行为,可以在 application.yml 配置文件中进行紧急调整:
spring:
jackson:
use-jackson2-defaults: true # 强制 Jackson 3 模拟 Jackson 2 的默认行为(不推荐长期使用)
请注意,这只是一个临时解决方案,旨在为彻底适配新格式争取时间。
4. 异常处理:Checked Exception 的终结
作为 Java 开发者,你一定写过大量被 try-catch 块包裹的 objectMapper.readValue() 代码,以处理 JsonProcessingException 这类检查型异常(Checked Exception)。Jackson 3 终于顺应了广大开发者的呼声,将序列化/反序列化过程中的主要异常都改为了 RuntimeException(具体是 JacksonException)。
对比感受一下代码的整洁度提升:
// Jackson 3:Stream API 和 Lambda 表达式的福音
list.stream()
.map(o -> jsonMapper.writeValueAsString(o)) // 此处不再强制要求捕获 IOException
.toList();
这一改动看似微小,但却是真正为现代 Java 编程范式(如 Stream API、Lambda 表达式)服务的设计,能够显著减少模板代码,提升代码的可读性和简洁性。
总结
一次优秀的框架升级,不应仅仅是追逐新版本,更要深入理解其背后的设计意图与工程权衡。Jackson 3 的这次重大升级,完美诠释了如何在理想主义(追求不可变性、运行时异常)与工程现实(兼容海量现有注解)之间取得平衡。
对于使用 Spring Boot 的开发者而言,在迈向 4.0 时,务必将 Jackson 3 的上述变更纳入升级检查清单。从包名、API使用习惯到数据格式,逐步适配,方能享受新版本带来线程安全与现代 API 的同时,确保服务的平稳过渡。如果你想了解更多关于框架升级与最佳实践的讨论,欢迎来 云栈社区 与其他开发者交流心得。