找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

4119

积分

0

好友

531

主题
发表于 1 小时前 | 查看: 3| 回复: 0

前言

最近在做 Spring Boot 4 升级时发现一个非常普遍的现象——大部分人被 Jackson 3 这个“隐形炸弹”炸得措手不及

项目启动后,控制台报了一堆莫名其妙的错。

翻来覆去一看,原来不是业务代码的问题,是 Jackson 升级带来的破坏性变更

“Jackson 不就是个 JSON 序列化工具吗?升级一下能有什么大不了的?”

如果你这么想,那说明你还没真正理解 Jackson 在 Java 生态中的位置。

Jackson 不仅仅是“一个 JSON 库”,它是 Java 生态中事实上的 JSON 标准实现

Spring Boot、微服务通信、Redis 序列化、日志解析——几乎所有涉及到 JSON 的地方,底层都在用 Jackson。

从 Jackson 2.x 升级到 3.x,不是一次“无感升级”。

它是 Jackson 时隔 8 年的第一次大版本号变更。

从 2017 年底开始酝酿,到 2025 年 10 月 3 日正式发布 GA 版本,前后经历了10 个 RC 版本

今天这篇文章,我就把 Jackson 3 的新功能和迁移要点从头到尾给你拆解一遍。

希望对你会有所帮助。

一、Jackson 3 到底“新”在哪?

在聊具体功能之前,我们先建立一个整体认知。

Jackson 3 是一次价值取向非常明确的重构型演进

如果说 Jackson 2 更偏向“兼容一切历史包袱”,那么 Jackson 3 的目标非常清晰——安全、类型清晰、面向现代 Java

Jackson 2.x 与 Jackson 3.x 核心变化对比

这张图基本概括了 Jackson 3 的核心变化

下面我逐一给你拆解。

二、JDK 基线升级到 Java 17

这是 Jackson 3 最根本的变化。Jackson 3.x 要求 JDK 17+

Jackson 2.x 最低支持 JDK 8。

从 JDK 8 到 JDK 17,中间隔了 9 年、4 个 LTS 版本。

这个升级意味着 Jackson 3 可以充分利用 Java 17 的新特性——Records、Sealed Classes、Pattern Matching 等。

对你的影响:如果你的项目还在 JDK 8 或 11 上,想用 Jackson 3,必须先升级 JDK。好消息是,Spring Boot 3.x 已经要求 JDK 17 了,所以大部分新项目其实已经满足了这个条件。

三、包名和 groupId 全面变更

这是最“显眼”的变更,也是你升级时第一个会碰到的编译错误

对比项 Jackson 2.x Jackson 3.x
Maven groupId com.fasterxml.jackson tools.jackson
Java 包名 com.fasterxml.jackson.xxx tools.jackson.xxx
注解包名 com.fasterxml.jackson.annotation 保持不变
// Jackson 2.x 的写法
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.core.JsonParser;

// Jackson 3.x 的写法
import tools.jackson.databind.json.JsonMapper;
import tools.jackson.core.JsonParser;

为什么注解包名不变?

这是一个非常巧妙的设计。Jackson 团队把注解库jackson-annotations)留在了原来的 groupId 和包名下,只把核心处理逻辑移到了 tools.jackson。Jackson 3.0 使用的是 jackson-annotations 2.20 版本。

这意味着:Jackson 2 和 Jackson 3 可以在同一个项目中共存。你的核心应用可以用 Jackson 3,老旧第三方依赖库依然可以用 Jackson 2,互不干扰。

但要注意一个例外:jackson-databind 内部的注解(如 @JsonSerialize@JsonDeserialize)会移动到新包 tools.jackson.databind.annotation

四、ObjectMapper 变成不可变的 JsonMapper

这是 Jackson 3 影响面最大的变更。

在 Jackson 2.x 中,ObjectMapper可变的。你可以这样写:

// Jackson 2.x - 可变配置
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);      // 随时可以改
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
// 状态可以在任何时候被修改

这种设计在多线程环境下会引发问题——一个线程修改了配置,另一个线程正在使用,就会出现不可预知的行为。

Jackson 3.x 强制使用 Builder 模式,构建完成后配置就被锁定了:

// Jackson 3.x - 不可变 Builder 模式
JsonMapper mapper = JsonMapper.builder()
    .enable(SerializationFeature.INDENT_OUTPUT)
    .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
    .build();  // 配置一旦 build() 就被锁定

Jackson 2.x 可变 ObjectMapper vs Jackson 3.x 不可变 Builder 模式

必须使用格式对齐的子类:在 Jackson 3 中,必须使用与数据格式匹配的 ObjectMapper 子类:

// Jackson 2.x - 可以混用
ObjectMapper mapper = new ObjectMapper(new YAMLFactory());

// Jackson 3.x - 必须使用对应的 Mapper
JsonMapper jsonMapper = JsonMapper.builder().build();   // JSON
YAMLMapper yamlMapper = YAMLMapper.builder().build();   // YAML
XmlMapper xmlMapper = XmlMapper.builder().build();      // XML

禁止 new ObjectMapper(new YAMLFactory()) 这种写法。

五、异常体系重构

Jackson 2.x 使用的是检查型异常(Checked Exception)——JsonProcessingExceptionException 的子类,你必须显式 try-catch 或 throws。

Jackson 3.x 改为非检查型异常(Unchecked Exception)

Jackson 2.x Jackson 3.x
JsonProcessingException JacksonException(基类)
JsonParseException StreamReadException
JsonEOFException UnexpectedEndOfInputException
// Jackson 2.x - 必须处理检查型异常
try {
    User user = mapper.readValue(json, User.class);
} catch (JsonProcessingException e) {
    // 必须处理
}

// Jackson 3.x - 非检查型异常,可以选择不捕获
User user = mapper.readValue(json, User.class);
// 如果出错,抛出 JacksonException(运行时异常)

这个改动让 Jackson 的 API 更符合现代 Java 编程习惯,和 Spring、Lombok 等主流框架保持一致。

六、默认配置全面调整

Jackson 3 改了大量默认配置

我挑几个最可能“炸到你”的来说。

6.1 日期序列化:从时间戳变成 ISO-8601 字符串

这是最容易被忽略、影响面最大的变更之一。

// Jackson 2.x 默认:2026-07-20 12:00:00 → 1721462400000(时间戳)

// Jackson 3.x 默认:2026-07-20 12:00:00 → "2026-07-20T12:00:00Z"(ISO-8601 字符串)

如果你的前端代码依赖时间戳格式,升级后接口返回的数据格式会变。好消息是,可以显式配置改回来:

JsonMapper mapper = JsonMapper.builder()
    .enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)  // 改回时间戳
    .build();

6.2 原始类型空值:从宽松变成严格

Jackson 3.x 将 FAIL_ON_NULL_FOR_PRIMITIVES默认值从 false 改为了 true

// 假设你有这样的 DTO
public class User {
    private int age;  // 原始类型 int
}

// Jackson 2.x:JSON 中 age 为 null 时,默认赋值为 0
// Jackson 3.x:JSON 中 age 为 null 时,抛出 JsonMappingException

这个变更会让很多“以前能跑”的代码突然报错。解决方案:要么把 int 改成 Integer,要么显式禁用这个特性。

6.3 月份计数:从 0 基变成 1 基

Java 的 java.util.Date 中,月份是从 0 开始的(0 = 一月)。Jackson 3.x 将 DateTimeFeature.ONE_BASED_MONTHS默认值从 false 改为了 true

这意味着序列化/反序列化时,月份的处理方式发生了变化。如果你的代码依赖“0 = 一月”的逻辑,升级后需要特别注意。

七、性能与内存优化

Jackson 3 不只是“改 API”,在性能和内存方面也做了大量优化。

7.1 BeanDescription 懒加载优化

Jackson 3.0 对 BeanDescription 的实现引入了 Supplier 模式实现延迟加载。对于简单类型或不需要完整 BeanDescription 的场景,避免了不必要的解析开销。这减少了临时对象的创建和 GC 压力。

7.2 RecyclerPool 延迟初始化

Jackson Core 3.0 优化了 RecyclerPool 的初始化策略。在高频使用 Jackson 的应用中,能显著提升内存使用效率。

7.3 字段名去重禁用

Jackson 3.0 将 TokenStreamFactory.Feature.INTERN_FIELD_NAMES默认值改为 false。这意味着 JSON 字段名不再被自动缓存到字符串常量池中,减少了内存占用。

八、模块整合:少了三个依赖

在 Jackson 2.x 中,为了支持 Java 8 的新特性,你需要额外引入三个模块:

<!-- Jackson 2.x 需要额外引入 -->
<dependency>
    <groupId>com.fasterxml.jackson.module</groupId>
    <artifactId>jackson-module-parameter-names</artifactId>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jdk8</artifactId>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
</dependency>

Jackson 3.x 中,这三个模块已经整合到 jackson-databind。不需要单独引入了。

九、破坏性变更速查表

我把 Jackson 3 中最可能让你的代码报错的变更整理成了一张速查表:

变更类型 Jackson 2.x Jackson 3.x 影响
基类异常 JsonProcessingException(检查型) JacksonException(非检查型) try-catch 需要改
ObjectMapper 可变,new 即可 不可变,必须 Builder 所有创建代码要改
包名 com.fasterxml.jackson tools.jackson 所有 import 要改
groupId com.fasterxml.jackson.core tools.jackson.core pom.xml 要改
日期默认 时间戳 ISO-8601 字符串 接口返回格式变
原始类型 null 允许(赋默认值) 抛异常 可能新增报错
ObjectCodec 存在 已移除 强转代码报错
JsonGenerator.writeObject() 存在 改为 writePOJO() 方法名要改
JsonParser.getCurrentLocation() 存在 改为 currentLocation() 方法名要改

十、优缺点与适用场景

Jackson 3 的优点

1. 线程安全有保障
JsonMapper 不可变,构建完成后配置锁定,可以在多线程环境下安全共享。

2. 面向现代 Java
JDK 17+ 基线,可以充分利用 Records、Sealed Classes 等新特性。

3. 默认配置更安全
日期输出 ISO-8601 更符合国际标准,原始类型空值检查更严格,多态类型验证更严格。

4. 性能优化
BeanDescription 懒加载、RecyclerPool 延迟初始化等多项优化。

5. 依赖精简
jackson-module-parameter-names、jackson-datatype-jdk8、jackson-datatype-jsr310 已整合到 databind。

6. 异常处理更简洁
非检查型异常,不需要到处 try-catch。

7. 生态正在快速跟进
Spring Boot 4 已默认使用 Jackson 3,Netflix DGS 等主流框架也已支持。

Jackson 3 的注意事项

1. 不是 LTS 版本
Jackson 3.0 是过渡版本,3.1 才是第一个 LTS 版本。生产环境建议直接升级到 3.1.x。

2. 破坏性变更极多
包名、类名、方法名、异常体系、默认配置全面变化,升级工作量不小。

3. 生态依赖拖后腿
很多第三方库还在用 Jackson 2,比如 Swagger。好消息是 Spring Boot 4 同时管理 Jackson 2 和 3 的依赖,可以共存。

4. 迁移需要系统规划
建议使用OpenRewrite 自动化迁移工具,或者配合 Spring 的 spring.jackson.use-jackson2-defaults 配置逐步过渡。

适用场景

场景 推荐程度 理由
新项目用 Spring Boot 4 ✅✅✅ 强烈推荐 Spring Boot 4 默认就是 Jackson 3
追求线程安全的高并发系统 ✅✅✅ 强烈推荐 JsonMapper 不可变,线程安全
需要现代 Java 特性 ✅✅✅ 强烈推荐 Records、Sealed Classes 等
老项目升级 Spring Boot 4 ⚠️ 需谨慎规划 破坏性变更多,建议用 OpenRewrite 辅助迁移
依赖大量 Jackson 2 生态库 ⚠️ 需评估 虽然可以共存,但需要额外配置

十一、迁移建议

如果你准备升级到 Jackson 3,我建议按这个顺序来:

第一步:升级 JDK 到 17+

这是硬性要求。如果还在 JDK 8/11,先升级 JDK。

第二步:升级 Spring Boot 到 4.x

Spring Boot 4 已经全面拥抱 Jackson 3。Spring Boot 4 同时管理 Jackson 2 和 3 的依赖,可以平滑过渡。

第三步:用 OpenRewrite 自动化迁移

# OpenRewrite 提供了 Jackson 2→3 的自动化迁移配方
mvn rewrite:run -DactiveRecipes=org.openrewrite.java.jackson.UpgradeJackson_2_3

第四步:利用过渡配置

Spring Boot 4 提供了 spring.jackson.use-jackson2-defaults 配置,可以暂时保持 Jackson 2 的默认行为,作为过渡期的“安全网”。

第五步:逐步替换代码

  • importcom.fasterxml.jacksontools.jackson(注解除外)
  • 改创建方式:new ObjectMapper()JsonMapper.builder().build()
  • 改异常处理:JsonProcessingExceptionJacksonException
  • 检查日期序列化:确认前端兼容 ISO-8601 格式

十二、写在最后

回到最初的问题:Jackson 3 来了,有哪些新功能?

它不是加了几个新注解、修了几个 Bug 那么简单。

Jackson 3 是一次彻底的架构升级——从 JDK 基线到包名、从 API 设计到异常体系、从默认配置到性能优化,全部重新梳理了一遍。

Jackson 3.0 于 2025 年 10 月 3 日正式发布 GA 版本,从 2017 年底开始酝酿,到正式发布经历了近 8 年的打磨。

而 Spring Boot 4 已经将其作为默认 JSON 库,整个 Java 生态正在加速向 Jackson 3 迁移。

但升级前要做好心理准备——Jackson 3 的破坏性变更非常多。包名变了、类名变了、方法名变了、异常类型变了、默认行为也变了。这不是一次“无感升级”。

好消息是,Spring Boot 4 同时管理 Jackson 2 和 3 的依赖,可以让你逐步迁移。Jackson 2.21 依然是 LTS 版本,短期内不会消失。

我的建议是:新项目直接上 Jackson 3;老项目跟随 Spring Boot 4 升级,利用 spring.jackson.use-jackson2-defaults 过渡,逐步完成迁移。如果依赖库太多、短期内无法全部升级,Jackson 2 和 3 共存也是可行的方案。

以上是 Jackson 3 的核心变化与迁移策略,更多 Java 技术栈升级深度文章,欢迎持续关注云栈社区。




上一篇:Linux 单机 TCP 连接上限:内核参数与百万并发解析
下一篇:联合索引覆盖了排序字段,为何仍有Using filesort?
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-7-24 06:54 , Processed in 0.875206 second(s), 41 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表