Java API for JSON Processing:JSON 简介

作者:Jitendra Kotamraju

Java API for JSON Processing 提供可移植的 API 来解析、生成、转换和查询 JSON。

2013 年 7 月发布

JSON(JavaScript 对象表示法)是一种轻量级的、基于文本的、独立于语言的数据交换格式,便于人类和机器进行阅读和编写。JSON 可以表示两种结构类型:对象数组。对象是零个或多个名称/值对的无序集合。数组是零个或多个值的有序序列。值可以是字符串、数字、布尔型、空值以及这两种结构化类型。

清单 1 是 Wikipedia 上的一个示例,显示了如何用 JSON 表示一个描述人的对象。该对象包含表示姓氏和名字的字符串、一个表示年龄的数值、一个表示此人地址的对象值以及一个表示电话号码对象的数组值。

{
    "firstName": "John",
    "lastName": "Smith",
    "age": 25,
    "address": {
        "streetAddress": "21 2nd Street",
        "city": "New York",
        "state": "NY",
        "postalCode": 10021
    },
    "phoneNumbers": [
        {
            "type": "home",
            "number": "212 555-1234"
        },
        {
            "type": "fax",
            "number": "646 555-4567" 
        }
    ] 
}

清单 1. 用 JSON 表示一个对象的示例

JSON 经常用于 Ajax 应用、配置、数据库以及 RESTful Web 服务。所有热门网站都提供 JSON 作为其 RESTful Web 服务的数据交换格式。

JSON 处理

Java API for JSON Processing (JSR 353) 使用对象模型 API 和流 API 提供可移植的 API 来解析、生成、转换和查询 JSON。

对象模型 API 创建一个随机存取的树状结构来表示内存中的 JSON 数据。然后可以对树进行导航和查询。这个编程模型是最灵活的,支持需要随机访问树的完整内容的处理。不过,它通常没有流模型那么高效,且需要更多内存。

流 API 以流方式解析和生成 JSON。它将解析和生成的控制权移交给程序员。流 API 提供一个基于事件的解析器,允许应用开发人员请求下一个事件,而不是在回调中处理该事件。这样,开发人员就可以更好地控制 JSON 处理过程。应用程序代码可处理或丢弃解析器事件,然后请求下一个事件(拉事件)。对于不需要随机访问数据其他部分的本地处理来说,流模型已经足够。类似地,流 API 通过一次写入一个事件将格式良好的 JSON 写入流中。

对象模型 API

对象模型 API 与 XML 文档对象模型 (DOM) API 类似。它是一个高级 API,为 JSON 对象和数组结构提供不可变对象模型。可以使用 Java 类型 JsonObjectJsonArray 将这两种 JSON 结构表示成对象模型。表 1 列出了对象模型 API 中主要的类和接口。

JsonObject 提供了一个 Map 视图,用于访问模型中零个或多个名称/值对的无序集合。类似地,JsonArray 提供了一个 List 视图,用于访问模型中零个或多个值的有序序列。

表 1. 对象模型 API 中主要的类
类或接口 说明
Json 包含用于创建 JSON 读取器、写入器、构建器及其工厂对象的静态方法。
JsonGenerator 将 JSON 数据写入流中,每次一个值。
JsonReader 从流中读取 JSON 数据,然后在内存中创建一个对象模型。
JsonObjectBuilder
JsonArrayBuilder
通过在应用程序代码中添加值,在内存中创建一个对象模型或数组模型。
JsonWriter 将内存中的一个对象模型写入流中。
JsonValue
JsonObject
JsonArray
JsonString
JsonNumber
代表 JSON 数据中值的数据类型。

JsonObjectJsonArrayJsonStringJsonNumber 都是 JsonValue 的子类型。这些常量都是在 API 中定义的,代表 null、true 和 false JSON 值。

对象模型 API 使用构建器模式从头开始创建这些对象模型。应用程序代码可以使用 JsonObjectBuilder 接口创建表示 JSON 对象的模型。生成的模型是 JsonObject 类型的。应用程序代码可以使用 JsonArrayBuilder 接口创建表示 JSON 数组的模型。生成的模型是 JsonArray 类型的。

也可以使用 JsonReader 接口从输入源(如 InputStreamReader)创建这些对象模型。同样,也可使用 JsonWriter 类将这些对象模型写入输出源(如 OutputStreamWriter)中。

例如,我们使用对象模型 API 编写搜索 Facebook 上公开帖子的代码。Facebook API 用清单 2 所示的 JSON 格式给出搜索结果:

1 {
2     "data" : [
3         { "from" : { "name" : "xxx", ... }, "message" : "yyy", ... },
4         { "from" : { "name" : "ppp", ... }, "message" : "qqq", ... },
5         ...
6     ],
7     ...
8 }

清单 2. 用 JSON 表示搜索 Facebook 公开帖子

我们可以使用对象模型 API 获取关于术语 java 的发帖人姓名及其公开帖子。在清单 3 中,第 1 至 3 行创建 JsonReader;第 5 行为结果创建 JsonObject;第 7 行对每个结果进行循环迭代;第 8 至 11 行获取发帖人的姓名、获取公开帖子并将它们打印出来。注意,该 API 中的 JsonReader 和其他对象可用在 try-with-resources 语句中(这又被称作自动资源管理 [ARM])。

 1 URL url = new URL("https://graph.facebook.com/search?q=java&type=post");
 2 try (InputStream is = url.openStream();
 3      JsonReader rdr = Json.createReader(is)) {
 4
 5     JsonObject obj = rdr.readObject();
 6     JsonArray results = obj.getJsonArray("data");
 7     for (JsonObject result : results.getValuesAs(JsonObject.class)) {
 8         System.out.print(result.getJsonObject("from").getString("name"));
 9         System.out.print(": ");
10         System.out.println(result.getString("message", ""));
11         System.out.println("-----------");
12     }
13 }

清单 3. 使用对象模型 API 处理 Facebook 帖子

流 API

流 API 与 Streaming API for XML (StAX) 类似,由接口 JsonParserJsonGenerator 组成。JsonParser 包含使用流模型解析 JSON 数据的方法。JsonGenerator 包含将 JSON 数据写入输出源的方法。表 2 列出了流 API 中主要的类和接口。

表 2. 流 API 中主要的类
类或接口 说明
Json 包含用于创建 JSON 解析器、生成器及其工厂对象的静态方法。
JsonParser 代表一个基于事件的解析器,可从流中读取 JSON 数据。
JsonGenerator 将 JSON 数据写入数据流,每次一个值。

JsonParser 使用拉解析编程模型对 JSON 数据进行前向只读访问。在该模型中,应用程序代码控制线程并调用解析器接口中的方法,以便向前移动解析器或者从解析器的当前状态获取 JSON 数据。

JsonGenerator 提供将 JSON 数据写入数据流的方法。可以使用生成器将名称/值对写入 JSON 对象,将值写入 JSON 数组。

流 API 是一个低级 API,旨在高效处理大量 JSON 数据。可使用该 API 实现其他 JSON 框架(如 JSON 绑定)。

我们使用流 API 执行与对象模型 API 相同的操作,即在 Facebook 上搜索关于 java 的公开帖子。在清单 4 中,第 1 至 3 行创建一个流解析器,第 4 至 5 行获取下一个事件,第 6 行查找 KEY_NAME 事件,第 8 至 11 行读取姓名并进行打印,第 14 至 16 行读取公开帖子并进行打印。与使用对象模型 API 执行相同的任务相比,使用流 API 可以更高效地访问发帖人姓名及其公开帖子。

 1 URL url = new URL("https://graph.facebook.com/search?q=java&type=post");
 2 try (InputStream is = url.openStream();
 3      JsonParser parser = Json.createParser(is)) {
 4     while (parser.hasNext()) {
 5         Event e = parser.next();
 6         if (e == Event.KEY_NAME) {
 7             switch (parser.getString()) {
 8                 case "name":
 9                     parser.next();
10                    System.out.print(parser.getString());
11                    System.out.print(": ");
12                    break;
13                case "message":
14                    parser.next();
15                    System.out.println(parser.getString());
16                    System.out.println("---------");
17                    break;
18             }
19         }
20     }
21 }

清单 4. 使用流 API 处理 Facebook 帖子

总结

Java API for JSON Processing 提供以下功能:

  • 将输入流解析成不可变对象或事件流
  • 将事件流或不可变对象写入输出流
  • 以编程方式导航不可变对象
  • 使用构建器以编程方式构建不可变对象

该 API 是构建数据绑定、转换、查询或其他操作 API 的基础。JAX-RS 2.0 为 Java API for JSON Processing 提供了原生集成。

另请参见

关于作者

Jitendra Kotamraju 是 Oracle 技术团队的主要成员,是 JSON 处理规范的带头人,并且还是 GlassFish 的主要工程师之一。在领导 JSON 处理项目之前,他主要负责 JAX-WS 2.2 规范和实现。

分享交流

请在 FacebookTwitterOracle Java 博客上加入 Java 社区对话!