好了,坐稳扶好,咱们进入今天的分享。
为什么 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 的 4 大 Breaking Changes
Spring Boot 4 默认升级到 Jackson 3 后,绝对不是换个版本号那么简单。下面这四个变化,如果不提前复盘,线上准得出 Bug。
1. 包名大重组:从com.fasterxml到tools.jackson
这是最直观的改动。所有的核心类都挪窝了:
// 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,那样你的注解就全报错了!
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(),配置就被彻底锁死。
这种设计让实例变得天然线程安全。如果你直接new ObjectMapper(),只能拿到默认配置,想自定义?对不起,请用 Builder。
3. 日期序列化更改
这是最容易导致前后端联调失败的地方。Jackson 3 改变了默认的日期输出格式:
| 维度 | Jackson 2 默认行为 | Jackson 3 默认行为 |
|---|---|---|
| 输出格式 | 时间戳 (Long) | ISO-8601 字符串 |
| 示例结果 | {"now": 1767588151648} | {"now": "2026-01-05T02:02:31Z"} |
避坑提醒:如果你的前端代码写死了按时间戳解析,或者测试用例里有硬编码的时间戳断言,升级后会全线崩掉。
【过渡方案】:如果你想保持现状,可以在application.yml里紧急救火:
spring: jackson: use-jackson2-defaults: true # 强制 Jackson 3 模拟 2 的行为,不推荐4. 异常处理:Checked Exception 的终结
作为 Java 开发者,你一定被try-catch包裹readValue恶心过。Jackson 3 终于顺应民意,把所有异常都改成了RuntimeException。
对比感受一下:
// Jackson 3:Lambda 表达式的福音 list.stream() .map(o -> jsonMapper.writeValueAsString(o)) // 不再强制 catch IOException .toList();这是真正为现代 Java 写法(Stream/Lambda)服务的设计。虽然看起来改动小,但对代码整洁度的提升是巨大的。
总结
好的框架升级,不应该只是追新,更要理解背后的设计意图。Jackson 3 的这次升级,完美诠释了什么是“在理想主义(线程安全、Runtime 异常)与工程现实(保留旧注解包名)之间跳舞”。