本博客日IP超过2000,PV 3000 左右,急需赞助商。
极客时间所有课程通过我的二维码购买后返现24元微信红包,请加博主新的微信号:xttblog2,之前的微信号好友位已满,备注:返现
受密码保护的文章请关注“业余草”公众号,回复关键字“0”获得密码
所有面试题(java、前端、数据库、springboot等)一网打尽,请关注文末小程序
【腾讯云】1核2G5M轻量应用服务器50元首年,高性价比,助您轻松上云
30 年了,Java 终于原生支持 JSON API 了。
回想一个多星期前,我写的 Fastjson 那篇文章引起了很多人讨论,其中有不少人提到了 Java 连原生的 JSON API 都没有,而 Python 和 Go,在处理 JSON 时,从不需要引入外包依赖。
这其中的原因可能有很多,我推测出的一个原因可能是,Java 出生时 JSON 并不流行,后来 JSON 流行了也是社区在推动,但这是社区里已经有比较优秀的类库了,以至于 Java 官方并不着急着推出原生的 JSON API。
随着时间的推进,现在 Java 终于要有内置 JSON API 了。这可是时隔十二年,Java 平台再次向内置 JSON 支持迈出关键一步。JEP 540(Simple JSON API)已从草案升格为 Candidate 状态,有望在 JDK 28 中以孵化器模块形式落地。
接下来,我们就一起来看看 Java 支持原生 JSON API 的前因后果,以及全面了解这个 API 的设计哲学、核心能力,以及它为何“做了减法”反而更值得期待。
一个迟到了 20 年的答案
2014 年,OpenJDK 提出了 JEP 198(Light-Weight JSON API),计划在 JDK 9 中引入轻量级 JSON API。然而,由于当时生态中 Jackson、Gson 等第三方库已相当成熟,这个提案最终被撤回,一放就是十余年。
十二年后的今天,JSON 早已成为 REST API、云原生应用、AI 服务调用的事实标准。Java 开发者面对一个简单的需求,比如从一段天气 API 响应中提取温度平均值,此时仍然要先引入一个外部依赖,配置 Maven/Gradle,才能写上几行解析代码。相比之下,Python 的 json 模块、Go 的 encoding/json 都是开箱即用。
这种“简单任务复杂化”的落差,正是 JEP 540 想要弥合的。
JEP 540
我看了一下 JEP 540 这个提案,它的核心目标可以概括为一句话:让 Java 处理简单 JSON 任务时,不再需要外部库,且代码与 Python/Go 一样简洁。
具体而言,它瞄准了以下几类痛点。
简单需求,引入其它依赖
很多时候,我们只需要做最简单的 JSON 操作。比如,解析一个 REST 响应、读取配置文件、构造一个 POST 请求体。为此引入 Jackson 或 Gson 或 Fastjson 等第三方类库,无异于“杀鸡用牛刀”,不仅增加依赖,还带来版本冲突、安全漏洞(如 Fastjson 的历史教训)、包体积膨胀等问题。
JDK 自身的 JSON 困境
一个容易被忽视的事实是 JDK 本身不能依赖任何外部库。这导致 JDK 内部至今仍在用一些相当“原始”的方式处理结构化数据。比如安全配置文件中,表达数组只能靠这种笨拙的编号方式。
security.provider.1=SUN
security.provider.2=SunRsaSign
security.provider.3=SunEC
如果 JDK 内置了 JSON 支持,这些配置完全可以变成:
{
"providers": ["SUN", "SunRsaSign", "SunEC"]
}
Java 平台演进
近年来,Java 在“减少样板代码”上做了大量工作。比如,var 推断、集合工厂方法(List.of、Map.of)、紧凑源文件、实例 main 方法等等,JEP 540 正是这一脉络的自然延伸。
也就是说,JEP 540 与 Java 平台“简化简单任务”的演进方向保持一致。
API 设计做减法,而非加法
JEP 540 最值得关注的地方,不是它“有什么”,而是它主动放弃了什么。
截止目前,官方明确了以下这些不做的事情,当然以后的事谁也说不好。
| 功能 | JEP 540 的态度 | 原因 |
|---|---|---|
| Data Binding(对象映射) | 不支持 | 大幅增加 API footprint,Jackson 已做得很好 |
| Streaming API | 不支持 | 简单场景不需要,且增加复杂度 |
| Trailing commas、Comments | 不支持 | 严格遵循 RFC 8259,保证互操作性 |
| 重复 Key 容忍 | 直接抛异常 | 消除歧义,避免安全漏洞 |
| JSON5 / 其他语法扩展 | 不支持 | 聚焦机器间通信,非人工编辑 |
一棵极简的 JSON 树
整个 API 围绕 JsonValue 这个 sealed 接口 展开,它有且仅有六个子类型。
JsonValue (sealed)
├── JsonString
├── JsonNumber
├── JsonBoolean
├── JsonNull
├── JsonObject
└── JsonArray
sealed 的设计非常关键,它保证了任何 JsonValue 实例必定是这六种之一,因此我们可以写出无需 default 分支的 exhaustive switch 表达式。
链式调用 + 快速失败
官方这次推出的 API,在访问与转换过程中,支持链式调用和快速失败。
import jdk.incubator.json.Json;
import jdk.incubator.json.JsonValue;
// 解析
JsonValue json = Json.parse(responseBody);
// 链式导航 + 提取
double avgTemp = json.get("properties")
.get("periods")
.asList()
.stream()
.mapToInt(j -> j.get("temperature").asInt())
.average()
.orElse(0);
这里的优雅之处有两点,无需向下转型和完整路径信息的异常。
get(String)和get(int)直接返回JsonValue,无需向下转型asInt()、asString()、asList()等转换方法在类型不匹配时,抛出带有完整路径信息的JsonValueException
比如,当我们错误地把数字当布尔值读取时,异常信息会打印出以下信息。
JsonNumber is not a JsonBoolean. Path: "{threadDump{threadContainers[0{threads[0{tid"
这种“fail fast + 清晰路径”的设计,在探索不熟悉的 JSON 文档时尤其有用。
处理不确定的结构
真实世界的 JSON 经常变化。JEP 540 提供了 tryGet 和 tryValue 来优雅处理可选字段和 null。
// 字段可能不存在
thread.tryGet("waitingOn")
.ifPresent(obj -> ...);
// 值可能是 null
container.get("parent").tryValue()
.ifPresent(name -> ...);
生成 JSON
生成 json 同样很简单,如下代码所示。
JsonObject.of(Map.of(
"providers",
JsonArray.of(List.of(
JsonString.of("SUN"),
JsonString.of("SunRsaSign")
))
)).toString();
// 输出: {"providers":["SUN","SunRsaSign"]}
输出方面官方提供了两种形式。toString() 输出紧凑格式,Json.toDisplayString(json, 2) 输出带缩进的可读格式。
严格遵守 RFC 8259
JEP 540 在解析策略上选择了最严格的立场。
- 零容忍重复 Key:一旦遇到对象中有重复的成员名,立即抛出
JsonParseException。RFC 8259 原文用的是SHOULD be unique(建议唯一),JEP 540 将其提升为硬性约束。理由是重复 Key 的文档在不同库中的行为不可预测,可能引发安全漏洞和难以诊断的 bug。 - 纯 RFC 8259,拒绝扩展。不支持 trailing commas、注释、单引号字符串等。如果你确实需要处理带注释的 JSON,JEP 甚至给出了一个预处理示例:
String jsonc = Files.readString(Path.of("file-with-comments.json"));
String json = jsonc.replaceAll("(?m)^\\s*#.*$", "");
JsonValue jv = Json.parse(json);
这种“严格输入、灵活处理”的策略,在最大程度上保证了与其他 JSON 库互操作时的行为一致性,更是为了高安全。
什么时候能用上?
截至 2026 年 8 月,JEP 540 已从 JEP Draft 提升至 Candidate 状态,正在 OpenJDK 社区审议中。
文章配图参见我的公众号:https://mp.weixin.qq.com/s/TY2VUvloehljRMTdeWjuDQ。
由于 JDK 27 的 JEP 已经冻结了,预计 2026 年 9 月发布,目前已进入 Rampdown 阶段,JEP 540 不太可能赶得上。
因此,JDK 28 很可能会加入这个 JEP。它预计在 2027 年 3 月发布,JEP 540 作为 孵化器(Incubator)模块 落地的可能性最大。届时需要通过 --add-modules jdk.incubator.json 启用。
作为孵化器特性,API 在后续版本中仍可能根据社区反馈进行调整,最终才会被纳入标准模块。
也就是说,这个 API 最快也要等到 JDK 29,这个长 LTS 版本才能正式可用,JDK 28 还需要参数加持才能体验到。
写在最后
不少人谈起 Java,就可能会诟病 Java 的原生 JSON 支持情况,以后可能会换说法了,比如说它不好用 🤣。但总比没有要好吧,而且链式调用,tryGet 等方法也还不错吧。
JEP 540 的提案中有还一句话令人印象深刻,The Python or Go code to accomplish such tasks is simple; the Java code should be equally simple,翻译过来就是完成这类任务,Python 或 Go 的代码很简单;Java 的代码也应该同样简单。
官方要表达的意思可能是在说,这不是一种“追赶”的焦虑,而是一种平台成熟度的自我要求。要知道,从 JEP 198(2014)到 JEP 540(2026),十二年间 Java 生态经历了微服务、云原生、AI 浪潮的洗礼,JSON 从一个“好用的数据格式”变成了整个数字世界的“通用语”。在这个时间点上,为 Java 平台补上一块“简单 JSON 处理”的基座,既是补课,也是面向下一个十年的铺垫。
对于我们 Java 开发者来说,JDK 28 之后,或许可以告别“为了一个 JSON 解析引入整个依赖树”的日子了。而对于 Jackson、Gson 的维护者们,这也未必是威胁。毕竟一个更健康的生态,应该是“简单需求零依赖,复杂需求有专业库”的分层结构。
让我们期待这个 JSON API 的尽快到来吧!

最后,欢迎关注我的个人微信公众号:业余草(yyucao)!可加作者微信号:xttblog2。备注:“1”,添加博主微信拉你进微信群。备注错误不会同意好友申请。再次感谢您的关注!后续有精彩内容会第一时间发给您!原创文章投稿请发送至532009913@qq.com邮箱。商务合作也可添加作者微信进行联系!
本文原文出处:业余草: » 再见 Fastjson,Java 原生 JSON API 来了