写点什么

JEP 540 提议在 JDK 28 中引入一个简单的 JSON API

作者:A N M Bazlur Rahman
  • 2026-08-25
    北京
  • 本文字数:1878 字

    阅读完需:约 6 分钟

JEP 540(简单 JSON API 孵化阶段)已经从候选状态变为 Proposed to Target ,并计划在 JDK 28 中交付。该提案将添加一个紧凑的、由 JDK 提供的 API,用于解析、遍历和生成 RFC 8259 JSON 文档而无需外部依赖。

如果该 API 的状态变为 Targeted 并成功交付后,它将包含在处于孵化阶段的 jdk.incubator.json 模块中,根据开发者的反馈,届时可能会有不兼容的特性更改或移除。该提案的功能范围刻意设计得比 JacksonGson 等库窄。它没有包含数据绑定和流式处理,也不提供宽松的解析模式或语法扩展支持。相反,它专注于常见任务,例如读取配置文件、检查 REST 响应或生成小型 JSON 有效载荷。

该 API 以 Json 类和 JsonValue 密封接口为核心。JsonValue 允许六种非密封子接口,分别表示 JSON 对象、数组、字符串、数字、布尔值和 null。其实例是不可变且线程安全的。

使用 Json.parse(String) 或 Json.parse(char[]) 解析完整的内存内文档时,会返回一个 JsonValue:

String body = ...; // JSON 响应体int temperature = Json.parse(body)    .get("properties")    .get("periods")    .get(0)    .get("temperature")    .asInt();
复制代码

该 API 的核心设计选择是在 JsonValue 上直接声明访问方法,这样调用方就可以遍历对象和数组,而无需反复对中间值做类型转换。若对非对象调用 get(String)、对非数组调用 get(int)、请求不存在的成员,或使用无效索引,都会抛出 JsonValueException 异常。

主要的易用性权衡体现在文档构建方面。JSON 值是通过相应接口中的工厂方法创建的:

JsonObject document = JsonObject.of(Map.of("service", JsonString.of("web_server"),"id", JsonNumber.of(3),"active", JsonBoolean.of(true)));
复制代码

对 JsonValue 调用 toString() 会生成紧凑的 JSON,而 Json.toDisplayString(...) 则会生成用于显示的格式化表示形式。这些显式的工厂方法明确了每个值的 JSON 类型,但也增加了操作复杂度,因为普通的 Java 字符串、数值和布尔值在放入对象或数组之前必须先进行封装。因此,文档构造过程的易用性很可能是孵化期间用户会提出反馈的一个方面。

严格性是另一个关键的选择。该解析器不提供宽松模式,它会拒绝注释、尾随逗号及其他语法扩展。它还会拒绝重复的对象成员名称,虽然 RFC 8259 规定名称应保持唯一,但并未作强制要求。否则,不同的解析器可能会保留第一个值、保留最后一个值、保留所有出现的情况,或者直接拒绝该文档。这使得名称重复成为互操作性的风险。

语法错误和名称重复会引发一个未检查的 JsonParseException 异常。该异常会记录错误发生的行号(从零开始计数)和位置。其公共 API 并未暴露结构化的 JSON 路径。

密封值层次结构也能很自然地与模式匹配组合使用。将标识符作为 JSON 数值或字符串输出的生成器可以通过类型-模式切换来处理:

long id = switch (json.get("id")) {    case JsonNumber number -> number.asLong();    case JsonString string -> Long.parseLong(string.asString());    default -> throw new JsonValueException("Unexpected id type");};
复制代码

转换方法遵循命名约定 as... 。asInt() 和 asLong() 要求目标类型的数值必须是其范围内的精确整数值。asDouble() 将数字转换为有限的 double 类型,但可能会进行舍入或丢失精度。asBoolean()、asMap() 和 asList() 分别将布尔值、对象和数组转换为 Java 值。map 和 list 视图是不可修改的,而且仍然包含 JsonValue 实例,而非递归转换后的 Java 基本类型。在错误的 JSON 类型上调用转换方法会抛出 JsonValueException 异常。

对于可选的对象成员,tryGet(String) 会返回一个 Optional 对象,当成员不存在时,该 Optional 为空。若对非 JSON 对象的值调用此方法,仍然会抛出 JsonValueException 异常。该 API 还会区分缺失的成员与显式包含的 JSON null 成员:对于后者,tryGet() 会返回一个包含 JsonNull 的 Optional;而对于 JsonNull,tryValue() 会返回一个空 Optional。

JEP 198(轻量级 JSON API)是 2014 年提出的一项功能覆盖范围更广的提案,但最终未能实现。新版设计侧重于不可变的内存值层次结构,并将对象映射、流处理、模式验证以及高级自定义功能交由现有的 JSON 生态系统去处理。

如果 JEP 540 进入 Targeted 状态并最终发布,类路径应用程序将需要通过 --add-modules jdk.incubator.json 显式加载该孵化器模块。孵化期将使 OpenJDK 社区能够在进一步推进该 API 之前,对导航模型、异常语义、数值转换以及文档构造易用性进行评估。

原文链接:https://www.infoq.com/news/2026/08/java-native-json-api/