Java 长期缺少一套随 JDK 提供、适合基础 JSON 处理的统一 API。JEP 540“Simple JSON API”目前已推进到 JDK 28 的 Target 状态,目标是让应用无需引入外部依赖,也能完成 JSON 文档的解析、遍历、类型转换和生成。
这项提案并不是要取代 Jackson、Gson 等成熟生态,而是填补 JDK 在轻量 JSON 任务上的空白。它强调紧凑接口、不可变值层次以及严格语法检查,并计划通过孵化阶段的使用反馈继续调整设计。
它瞄准的是基础 JSON 任务
不少 Java 程序引入 JSON 库,只是为了读取一个配置文件、解析一段 HTTP 响应,或者生成少量结构化数据。依赖本身未必很重,但团队随后还要处理版本管理、安全更新、模块声明和部署体积等问题。
JEP 540 希望把这些核心能力放进 JDK:
- 将 JSON 文本解析为结构化值;
- 遍历对象和数组;
- 把字符串、数字、布尔值等节点转换为 Java 值;
- 生成符合 JSON 语法的文档;
- 对错误语法执行严格检查,而不是静默接受非标准输入。
这里的关键词是“Simple”。从来源摘要能够确认的是核心方向,而不是完整的对象映射、注解绑定、流式处理或复杂扩展机制。因此,不能仅凭该提案就假定它会覆盖成熟第三方库的全部能力。
不可变值层次会改变使用方式
JEP 540 提供不可变的 JSON 值层次。这意味着解析后的对象、数组和标量值不会被调用者就地修改。不可变设计对服务端程序尤其有价值:同一棵 JSON 树可以在多个方法或线程间传递,而不必担心某个调用者悄悄改写内容。
代价也很明确。需要修改文档时,程序通常要创建一个新值,或者通过构建器重新生成相关结构。对于小型配置和普通 API 响应,这种成本通常可以接受;对于超大文档或高频局部更新,则应重点观察内存分配和复制开销。
不可变值层次还适合与 Java 的模式匹配结合。应用可以按照对象、数组、字符串、数字、布尔值和 null 等节点类型分支处理,而不是依赖大量未经检查的类型转换。不过,具体类型名和方法仍应以 JDK 28 实际发布的 API 为准。
可以这样隔离尚未定稿的 API
JEP 540 仍将通过孵化反馈塑造后续设计,公开类型名和调用方式可能变化。现在评估它时,可以先在业务代码与 JSON 实现之间放置一个很薄的边界。
下面是一个可直接编译运行的 Java 示例。它不虚构 JEP 540 尚未从摘要中确认的类名,而是演示如何把 JSON API 限制在一个适配器中。等 JDK 28 构建提供实际 API 后,只需要替换 JdkJsonCodec 内部实现。
import java.util.Map;
public class Main {
interface JsonCodec {
Map<String, Object> parseObject(String document);
String generateObject(Map<String, Object> value);
}
static final class JdkJsonCodec implements JsonCodec {
@Override
public Map<String, Object> parseObject(String document) {
// 在 JDK 28 评估版本中替换为 JEP 540 的实际解析调用。
throw new UnsupportedOperationException(
"Connect this adapter to the JDK 28 Simple JSON API");
}
@Override
public String generateObject(Map<String, Object> value) {
// 在这里集中处理 JEP 540 的值构造与文档生成。
throw new UnsupportedOperationException(
"Connect this adapter to the JDK 28 Simple JSON API");
}
}
public static void main(String[] args) {
JsonCodec codec = new JdkJsonCodec();
try {
codec.parseObject("{\"service\":\"billing\",\"enabled\":true}");
} catch (UnsupportedOperationException e) {
System.out.println(e.getMessage());
}
}
}
将文件保存为 Main.java 后,可以这样运行:
javac Main.java
java Main
这种边界还能避免把 JSON 树节点扩散到领域模型中。控制器或文件读取器负责解析,业务层只接收明确的 Java 类型;将来更换 JDK API、Jackson 或其他实现时,改动范围会小得多。
等获得包含 JEP 540 的 JDK 28 构建后,可以先检查运行环境,再根据该构建的模块和文档调整编译参数:
java --version
java --list-modules | grep -i json || true
如果该 API 以孵化模块交付,编译和运行时通常需要显式添加对应模块;准确模块名和启用方式必须以所测试的 JDK 28 构建为准,不应提前写死。
严格解析值得单独测试
“严格语法规则”不仅是实现细节,也会影响系统兼容性。一些既有 JSON 库可以配置为接受注释、尾随逗号、单引号、未加引号的字段名或特殊数字值。严格解析器应拒绝这些扩展格式。
接入时至少要准备以下测试数据:
合法:{"name":"api","ports":[8080,8081],"enabled":true}
非法:{"name":"api",}
非法:{'name':'api'}
非法:{"threshold":NaN}
非法:{"note":"bad
line"}
这些用例可以帮助团队发现历史数据是否依赖宽松语法。对外部输入而言,严格规则通常能减少歧义;对内部遗留配置而言,它也可能带来迁移成本。不要在升级 JDK 后直接替换生产解析器,应先对真实样本做回放测试。
采用时看清边界
JEP 540 进入 Target 状态,意味着它正朝 JDK 28 集成推进,但这不等于 API 已经永久定型。团队可以开始验证其可用性,却不宜在预览或孵化阶段让具体类型遍布整个代码库。
评估时可以使用这份清单:
- 场景是否只是解析、遍历和生成普通 JSON;
- 是否需要注解驱动的对象映射;
- 是否需要流式处理超大文档;
- 输入是否包含非标准 JSON 扩展;
- 不可变树在目标负载下是否产生可接受的分配开销;
- 是否能通过适配器隔离孵化 API 的变化;
- 是否已经针对错误输入、深层嵌套和大数字建立测试。
对于 JDK 工具、小型服务、命令行程序和基础设施组件,内置 JSON API 能减少依赖并统一基本行为。对于复杂数据绑定、高性能流式处理或已有成熟 Jackson 配置的系统,第三方库仍可能是更合适的选择。JEP 540 真正值得关注的地方,不是“JDK 终于能处理 JSON”这一口号,而是 Java 平台开始提供一个足够小、足够严格、可以被基础代码可靠依赖的共同接口。