版本更新预告:Apache IoTDB 将最低 JDK 提升至 17,并完成 javax → jakarta 迁移

14 min

写在前面

这不是一篇已发布版本的解析,而是一篇预告

apache/iotdb#17859 已经合并到 master 分支,标题是 “Upgrade minimum JDK to 17 and migrate JavaX to Jakarta”。它不会带来任何用户可见的新功能,但它动了一个比新功能更”伤筋动骨”的东西——项目的运行时基线

  • 最低 Java 版本从 JDK 8 / 11 的混合基线,统一提升到 JDK 17
  • REST 服务、OpenAPI 生成代码以及 Jakarta EE 运行时 API,从 javax.* 全面迁移到 jakarta.*
  • 一大批锁定依赖随之升级:Jetty 12 EE10、Jersey 3、Logback 1.5、ANTLR 4.13、OpenAPI Generator 7、Swagger / Jackson 的 Jakarta 变体。

这类变更有一个共同特征:平时没人会主动碰它,但越拖越贵。本文不讲”新特性怎么用”,而是讲清楚三件事:

  1. 为什么是 JDK 17,而不是继续躺在 JDK 8 上?
  2. javax → jakarta 这一行 import 的改名,为什么会牵动两百多个文件?
  3. 对于已经在生产环境跑着 IoTDB 的人,这次基线变更意味着什么?

本文基于已合并的 PR #17859。由于该变更刚进入 master、尚未随某个正式版本发布,文中的目标版本号(如 TsFile 2.3.2)以 PR 中的快照为准,正式发布时可能微调。


一、为什么是 JDK 17:一次”还技术债”的动作

IoTDB 长期把 JDK 8 作为最低支持版本——这在 Java 大数据生态里并不少见,Hadoop、早期 Flink 都背着同样的历史包袱。但到 2026 年,继续停留在 JDK 8 / 11 的代价已经越来越难忽视。

1.1 生命周期:旧版本正在变成”付费才有补丁”

先看一张 LTS 版本的支持时间线(以 Oracle 口径为主,下游厂商如 Amazon Corretto、Azul、Adoptium 各有差异):

版本免费公共更新窗口Oracle 商业支持周期现状
JDK 8OpenJDK 8 社区更新逐步收尾商业 EOL 拖到 2030+免费补丁基本断供,靠付费续命
JDK 11免费社区更新约 2024-09 终止Premier 2023-09 结束,扩展支持到 2032免费窗口已关,续命需订阅
JDK 17生产免费窗口至 2024-09Premier 约 2026-09,总计到 2029仍在主流维护期内

表中”免费公共更新窗口”指 Oracle JDK 免费用于生产的截止点,“商业支持周期”指付费订阅可获得补丁的区间——两者是不同维度,前者先关、后者后结束。下游厂商(Amazon Corretto、Azul、Adoptium 等)各自的免费窗口通常更长,需按实际发行版确认。

这张表想说的不是”JDK 17 永远安全”,而是一个更现实的判断:JDK 8 / 11 早已越过免费安全补丁的分水岭。继续把它们作为最低基线,意味着官方要为一批拿不到上游安全更新的运行时持续做兼容性维护——这对一个时序数据库项目来说是纯粹的负担。

把最低门槛抬到 JDK 17,本质是把”还能拿到主流安全更新”作为底线:让项目运行在一个仍在被积极打补丁的 JVM 上,而不是停留在一个连上游都不再免费修复的版本里。安全收益的关键不在某几个具体漏洞编号,而在补丁通道是否还畅通——JDK 8 / 11 的免费补丁通道已经关闭,JDK 17 还开着。

1.2 真正的连锁反应:依赖生态在抛弃旧 JDK

比 JVM 自身 EOL 更有压迫感的,是第三方库正在集体上调最低 JDK 要求。这正是 PR #17859 里那一长串依赖升级的根本驱动:

  • Jetty 12 / EE10 要求 JDK 17+;
  • Jersey 3.x(JAX-RS 实现)跟随 Jakarta EE 9+,告别 javax
  • Logback 1.5Jackson 的 Jakarta RS provider、Swagger 的 Jakarta 变体,全部围绕 jakarta.* 命名空间重建。

换句话说,IoTDB 即便不主动升 JDK,它依赖的 Web/REST 技术栈也已经没有还停留在 JDK 8 + javax 的新版本可用了。继续锁在老版本,等于放弃这些库后续的安全修复和 bug 修复。

所以这次变更的逻辑链条是:

依赖库停止支持 JDK 8 / javax

想升级依赖 → 必须升 JDK + 换命名空间

最低基线提到 JDK 17 + 全量迁移 jakarta

JDK 17 在这里不是”追新”,而是被生态推着走的最低代价选择。


二、javax → jakarta:一行改名,两百个文件

很多人第一次听说 javax → jakarta 会有个直觉:不就是 import 改个前缀吗,IDE 全局替换一下不就完了?

要理解为什么 PR #17859 会触及两百多个文件,得先搞清楚这次改名的性质

2.1 这是一次”商标驱动”的断裂,不是技术升级

2019 年,Oracle 把 Java EE 捐给了 Eclipse 基金会,但保留了 javax 这个命名空间的商标权。于是从 Jakarta EE 9 开始,所有企业级 EE API 的包名被迫从 javax.* 改成 jakarta.*

// 旧(Java EE / javax)
import javax.ws.rs.GET;
import javax.validation.constraints.NotNull;
import javax.annotation.Generated;

// 新(Jakarta EE 9+ / jakarta)
import jakarta.ws.rs.GET;
import jakarta.validation.constraints.NotNull;
import jakarta.annotation.Generated;

关键在于,这是一次不向后兼容的硬断裂

  • Jakarta EE 9 之后的服务器(Tomcat 10、Jetty 12 等)只认 jakarta.*,不再识别 javax.*
  • 同一个类,javax 版和 jakarta 版在 classpath 上是两个完全不同的类,混用会直接抛 ClassNotFoundException / NoClassDefFoundError
  • 规范本身不保证任何向后兼容,要不要兼容由各实现自己决定——而主流实现选择了”不兼容”。

这就是为什么”全局替换前缀”看起来简单,实际却是一次需要逐模块验证的迁移。

2.2 IoTDB 这次迁移触及了哪些角落

从 PR 的改动范围看,迁移并不局限于 REST 接口,而是渗透到了几个层次:

层次涉及内容javax → jakarta 的体现
REST / JAX-RSexternal-service-impl/restrest-openapijavax.ws.rs.*jakarta.ws.rs.*
校验注解iotdb-core(datanode / confignode / consensus)javax.validationjakarta.validation
OpenAPI 生成代码OpenAPI Generator 7 重新生成生成模板切换到 jakarta
Thrift 协议模块多个 thrift-* 模块见下方”踩坑点”

2.3 一个值得记下来的踩坑点:Thrift 的 @Generated

迁移里有个细节很能说明”硬断裂”的麻烦之处。

代码生成器(Thrift)会在生成的类上打 @Generated 注解。这个注解在 jakarta 体系下应该是 jakarta.annotation.Generated,但 Thrift 0.14.1 还不认识这个 jakarta 版本的注解。结果就是:迁移到 jakarta 后,Thrift 生成的代码反而带上了一个它自己不支持的注解。

PR 的处理方式是抑制掉 Thrift 生成代码里的 @Generated 注解——绕开这个工具链尚未跟上的缺口。

这类”A 升级了但 B 还没跟上”的缝隙,正是 javax → jakarta 迁移在真实大型项目里最耗时的部分:改 import 是机械劳动,处理工具链断层才是真功夫

进展跟进:工具链正在补上这个缺口

“抑制注解”只是临时绕行,真正的根治是把 Thrift 编译器本身升上去。就在 #17859 合并前后,IoTDB 的 Thrift 工具链也在同步推进——apache/iotdb-bin-resources#68(已合并)发布了基于 Apache Thrift 0.23.0 的编译器产物 iotdb-tools-thrift 0.23.0.0,并配套了多平台 CI 构建流程。

也就是说,IoTDB 用的 Thrift 工具链正从 0.14.x 一代向 0.23.0 演进。等新工具链全面落地,前面那个”只能抑制 @Generated”的临时手段,未来有望被更彻底的方案取代。这条线是独立仓库、独立进度,属于这次基线升级的配套工程——值得放在一起看,但不必和主 PR 绑死。

另外两个值得注意的边界(PR 中明确保留,没有动):

  • JSR-305 注解javax.annotation.Nonnull / Nullable保留不动——它们是纯静态分析注解,不属于 EE 运行时,也不阻碍迁移;
  • REST 示例和集成测试里的 Apache HttpClient 保持原样——它本就不在 javax/jakarta 命名空间之列。

能分清”哪些必须改、哪些不该碰”,是这类迁移做得干净的标志。


三、对生产环境意味着什么

如果你正在生产环境跑 IoTDB,这次基线变更落到正式版本后,有几件事需要提前规划。

3.1 升级前的检查清单

□ 运行时 JVM 是否已是 JDK 17+?
   └─ 这是硬门槛。新版本将不再支持 JDK 8 / 11 启动。

□ 启动脚本是否依赖特定 JAVA_VERSION 行为?
   └─ PR 中已修复 Windows 启动脚本对空 JAVA_VERSION 的处理,
      自定义过启动脚本的环境需对照检查。

□ 是否有外挂的、依赖 IoTDB REST 接口的集成?
   └─ REST 服务底层从 Jersey 2/javax 换到 Jersey 3/jakarta,
      对外 HTTP 契约不变,但若你打包进了同一 JVM 进程、
      或基于内部类做过扩展,需要重新验证。

□ 自定义插件 / UDF 是否引用了 javax.* 的 EE 注解?
   └─ 若有,需同步迁移到 jakarta.*。

3.2 谁会”无感”,谁要”留神”

  • 纯客户端用户(通过 JDBC / Session / 各语言客户端连接):基本无感。命名空间迁移发生在服务端内部,对外协议不变。你只需确保部署 IoTDB 的那台机器装了 JDK 17+。
  • 运维 / 部署方:核心动作就一个——把运行 IoTDB 的 JVM 升到 17+。这是这次变更对绝大多数人唯一的实质影响。
  • 二次开发 / 插件作者:需要 review 自己的代码里是否用到了 javax.* 的 EE 注解(校验、JAX-RS 等),并跟随迁移。

3.3 一句话建议

对运维而言,这次变更的本质是:“换 JVM” 比 “换版本” 更重要。 先把目标环境的 JDK 准备到 17+,正式版本发布后的升级才会顺滑。


四、小结

PR #17859 是一次典型的”基线还债”——没有炫目的新功能,却把项目从一个逐渐失去安全更新和生态支持的旧基线上,拉到了一个仍被主流积极维护的位置。

三个要点回顾:

  1. JDK 17 是被生态推着走的最低代价:核心收益是”补丁通道还畅通”——JDK 8 / 11 的免费安全更新已断供,且依赖库也不再为 JDK 8 / javax 出新版本。
  2. javax → jakarta 是商标驱动的硬断裂:不向后兼容,触及 REST、校验注解、OpenAPI、Thrift 多个层次,最耗时的不是改 import,而是处理 Thrift 这类工具链断层。
  3. 对生产环境,核心动作只有一个:把运行 IoTDB 的 JVM 升到 JDK 17+,其余大多无感。

等这次变更正式随版本发布,我会再写一篇结合实际升级体验的跟进。


延伸阅读