Java JSON 处理教程
原文:http://zetcode.com/java/jsonp/
Java JSON 处理教程展示了如何使用 JSON-P 库来处理 JSON。 这些示例将 Java 对象写入 JSON 文件,并将 JSON 数据读取到 Java 对象。 在作者的 Github 仓库中提供了代码示例。
JSON-P
用于 JSON 处理的 Java API(JSON-P)提供可移植的 API,以使用对象模型和流式 API 来解析,生成,转换和查询 JSON。 JSON-P 中使用 JSON 的两种方式有两种:流式 API 和对象模型 API。
JSON-P 流式 API
流式 API 将解析和生成控制移交给程序员。 流式 API 提供了基于事件的解析器,并允许应用开发者请求下一个事件,而不是在回调中处理该事件。 这称为拉方法。
名称 | 描述 |
---|---|
Json |
包含用于创建 JSON 解析器,生成器及其工厂的静态方法。 |
JsonParser |
表示一个基于事件的解析器,它从流中读取 JSON 数据。 |
JsonGenerator |
将 JSON 数据一次写入一个值。 |
JSON-P 对象模型 API
对象模型 API 创建一个树形结构,表示内存中的 JSON 数据。 可以灵活地导航和查询树。 另一方面,对象模型 API 的效率通常不如流模型,并且需要更多的内存。
名称 | 描述 |
---|---|
Json |
包含用于创建 JSON 解析器,生成器及其工厂的静态方法。 |
JsonObjectBuilder |
通过添加应用代码中的值在内存中创建对象模型。 |
JsonArrayBuilder |
通过添加应用代码中的值在内存中创建数组模型。 |
JsonReader |
从输入源读取JsonObject 或JsonArray 。 |
JsonWriter |
将JsonObject 或JsonArray 写入输出源。 |
JsonValue
,JsonObject
,JsonArray
,JsonString
和JsonNumber
是 JSON 数据类型。
在我们的示例中,我们使用 JDK 11 和 Maven 创建我们的应用。
<dependencies>
<dependency>
<groupId>javax.json</groupId>
<artifactId>javax.json-api</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<version>1.1</version>
</dependency>
</dependencies>
在项目中,我们使用javax.json-api
和javax.json
依赖项。
JSON-P JsonObjectBuilder
示例
在第一个示例中,我们使用对象生成器创建 JSON 字符串。
JsonObjectBuilderEx.java
package com.zetcode;
import javax.json.Json;
import java.time.LocalDate;
public class JsonObjectBuilderEx {
public static void main(String[] args) {
var born = LocalDate.of(1992, 3, 2).toString();
var json = Json.createObjectBuilder()
.add("name", "John Doe")
.add("occupation", "gardener")
.add("born", born).build();
var result = json.toString();
System.out.println(result);
}
}
JSON 字符串被打印到控制台。
var json = Json.createObjectBuilder()
.add("name", "John Doe")
.add("occupation", "gardener")
.add("born", born).build();
用createObjectBuilder()
创建一个JsonObjectBuilder
。 新的对将插入add()
。 最后,使用build()
结束字符串。
var result = json.toString();
我们使用toString()
将JsonObject
转换为字符串。
{"name":"John Doe","occupation":"gardener","born":"1992-03-02"}
这是输出。
PRETTY_PRINTING
通过JsonGenerator.PRETTY_PRINTING
配置设置,我们可以设置写入器进行漂亮的打印。
JsonPrettyPrintEx.java
package com.zetcode;
import javax.json.Json;
import javax.json.stream.JsonGenerator;
import java.io.StringWriter;
import java.time.LocalDate;
import java.util.HashMap;
public class JsonPrettyPrintEx {
public static void main(String[] args) {
var born = LocalDate.of(1992, 3, 2).toString();
var json = Json.createObjectBuilder()
.add("name", "John Doe")
.add("occupation", "gardener")
.add("born", born).build();
var config = new HashMap<String, Boolean>();
config.put(JsonGenerator.PRETTY_PRINTING, true);
var jwf = Json.createWriterFactory(config);
var sw = new StringWriter();
try (var jsonWriter = jwf.createWriter(sw)) {
jsonWriter.writeObject(json);
System.out.println(sw.toString());
}
}
}
在示例中,我们创建一个 JSON 对象并将其打印到控制台。 输出打印精美。
var config = new HashMap<String, Boolean>();
config.put(JsonGenerator.PRETTY_PRINTING, true);
var jwf = Json.createWriterFactory(config);
配置文件被传递到JsonWriterFactory
。
{
"name": "John Doe",
"occupation": "gardener",
"born": "1992-03-02"
}
这是输出。
JSON-P JsonArrayBuilder
JsonArrayBuilder
是用于创建和修改JsonArray
对象的构建器。
JsonArrayBuilderEx.java
package com.zetcode;
import javax.json.Json;
import javax.json.stream.JsonGenerator;
import java.io.StringWriter;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.List;
public class JsonArrayBuilderEx {
public static void main(String[] args) {
var ab = Json.createArrayBuilder();
var users = createUsers();
users.forEach(user -> {
var ob = Json.createObjectBuilder();
ob.add("name", user.getName());
ob.add("occupation", user.getOccupation());
ob.add("born", user.getBorn().toString());
ab.add(ob);
});
var config = new HashMap<String, Boolean>();
config.put(JsonGenerator.PRETTY_PRINTING, true);
var jwf = Json.createWriterFactory(config);
var sw = new StringWriter();
try (var jsonWriter = jwf.createWriter(sw)) {
jsonWriter.writeArray(jsonArray);
System.out.println(sw);
}
}
public static List<User> createUsers() {
var born1 = LocalDate.of(1992, 3, 2);
var u1 = new User("John Doe", "gardener", born1);
var born2 = LocalDate.of(1967, 11, 22);
var u2 = new User("Brian Flemming", "teacher", born2);
var born3 = LocalDate.of(1995, 4, 7);
var u3 = new User("Lucy Black", "accountant", born3);
var born4 = LocalDate.of(1972, 8, 30);
var u4 = new User("John Doe", "gardener", born4);
return List.of(u1, u2, u3, u4);
}
}
在该示例中,我们创建了一个用户对象列表,并将其转换为JsonArray
。
var ab = Json.createArrayBuilder();
用createArrayBuilder()
创建一个JsonArrayBuilder
。
users.forEach(user -> {
var ob = Json.createObjectBuilder();
ob.add("name", user.getName());
ob.add("occupation", user.getOccupation());
ob.add("born", user.getBorn().toString());
ab.add(ob);
});
在此for
循环中,我们创建 JSON 对象并将其添加到构建器中。
var jsonArray = ab.build();
build()
方法从构建器创建JsonArray
。
jsonWriter.writeArray(jsonArray);
JsonArray
被写入写入器。
[
{
"name": "John Doe",
"occupation": "gardener",
"born": "1992-03-02"
},
{
"name": "Brian Flemming",
"occupation": "teacher",
"born": "1967-11-22"
},
{
"name": "Lucy Black",
"occupation": "accountant",
"born": "1995-04-07"
},
{
"name": "John Doe",
"occupation": "gardener",
"born": "1972-08-30"
}
]
这是输出。
JSON-P JsonParser
JsonParser
使用请求解析编程模型解析 JSON。 在此模型中,客户端代码控制线程并在处理每个元素之后调用方法next()
将解析器前进到下一个状态。
解析器生成以下事件之一:START_OBJECT
,END_OBJECT
,START_ARRAY
,END_ARRAY
,KEY_NAME
,VALUE_STRING
,VALUE_NUMBER
,VALUE_TRUE
,VALUE_FALSE
和VALUE_NULL
。
users.json
[
{
"name": "John Doe",
"occupation": "gardener",
"born": "1992-03-02"
},
{
"name": "Brian Flemming",
"occupation": "teacher",
"born": "1967-11-22"
},
{
"name": "Lucy Black",
"occupation": "accountant",
"born": "1995-04-07"
},
{
"name": "William Bean",
"occupation": "pilot",
"born": "1977-10-31"
}
]
我们将解析users.json
文件。
JsonParserSimpleEx.java
package com.zetcode;
import javax.json.Json;
import javax.json.stream.JsonParser;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.nio.charset.StandardCharsets;
public class JsonParserSimpleEx {
public static void main(String[] args) throws FileNotFoundException {
var is = new FileInputStream("src/main/resources/users.json");
var factory = Json.createParserFactory(null);
var parser = factory.createParser(is, StandardCharsets.UTF_8);
if (!parser.hasNext() && parser.next() != JsonParser.Event.START_ARRAY) {
return;
}
// looping over object attributes
while (parser.hasNext()) {
var event = parser.next();
// starting object
if (event == JsonParser.Event.START_OBJECT) {
while (parser.hasNext()) {
event = parser.next();
if (event == JsonParser.Event.KEY_NAME) {
var key = parser.getString();
switch (key) {
case "name":
parser.next();
System.out.printf("Name: %s%n", parser.getString());
break;
case "occupation":
parser.next();
System.out.printf("Occupation: %s%n", parser.getString());
break;
case "born":
parser.next();
System.out.printf("Born: %s%n%n", parser.getString());
break;
}
}
}
}
}
}
}
在示例中,我们使用 JSON-P 流式 API 解析users.json
文件。
var is = new FileInputStream("src/main/resources/users.json");
var factory = Json.createParserFactory(null);
var parser = factory.createParser(is, StandardCharsets.UTF_8);
从JsonParserFactory
创建一个JsonParser
。
if (!parser.hasNext() && parser.next() != JsonParser.Event.START_ARRAY) {
return;
}
首先,我们传递数组的开头。
// looping over object attributes
while (parser.hasNext()) {
var event = parser.next();
// starting object
if (event == JsonParser.Event.START_OBJECT) {
...
然后,我们在while
循环中遍历数组。 当我们到达数组末尾时,解析器的hasNext()
方法返回false
。 我们使用next()
拉下一个解析事件。
while (parser.hasNext()) {
event = parser.next();
if (event == JsonParser.Event.KEY_NAME) {
...
在另一个while
循环中,我们遍历当前对象的键。
var key = parser.getString();
switch (key) {
case "name":
parser.next();
System.out.printf("Name: %s%n", parser.getString());
break;
...
在switch
语句中,我们检查键名称,并通过getString()
获得其值。
Name: John Doe
Occupation: gardener
Born: 1992-03-02
Name: Brian Flemming
Occupation: teacher
Born: 1967-11-22
Name: Lucy Black
Occupation: accountant
Born: 1995-04-07
Name: William Bean
Occupation: pilot
Born: 1977-10-31
这是输出。
在第二个示例中,我们连接到网站并从路径获取 JSON 数据。
JsonParserEx.java
package com.zetcode;
import javax.json.Json;
import javax.json.stream.JsonParser;
import java.io.IOException;
import java.net.URL;
public class JsonParserEx {
public static void main(String[] args) throws IOException {
var url = new URL("https://jsonplaceholder.typicode.com/posts");
try (var in = url.openStream(); var parser = Json.createParser(in)) {
// starting array
parser.next();
while (parser.hasNext()) {
// starting object
var event1 = parser.next();
if (event1 == JsonParser.Event.START_OBJECT) {
while (parser.hasNext()) {
var event = parser.next();
if (event == JsonParser.Event.KEY_NAME) {
switch (parser.getString()) {
case "userId":
parser.next();
System.out.printf("User Id: %d%n", parser.getInt());
break;
case "id":
parser.next();
System.out.printf("Post Id: %d%n", parser.getInt());
break;
case "title":
parser.next();
System.out.printf("Post title: %s%n", parser.getString());
break;
case "body":
parser.next();
System.out.printf("Post body: %s%n%n", parser.getString());
break;
}
}
}
}
}
}
}
}
该示例处理了 jsonplaceholder.typicode.com 网站上的一百个帖子,该网站是用于测试和原型制作的虚假在线 REST API。
JSON-P JsonGenerator
JsonGenerator
以流方式将 JSON 数据写入输出源。 JsonGeneratorFactory
包含创建JsonGenerator
实例的方法。
JsonGeneratorEx.java
package com.zetcode;
import javax.json.Json;
import javax.json.stream.JsonGenerator;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.List;
public class JsonGeneratorEx {
public static void main(String[] args) throws IOException {
var myPath = Paths.get("src/main/resources/users.json");
var config = new HashMap<String, Boolean>();
config.put(JsonGenerator.PRETTY_PRINTING, true);
var factory = Json.createGeneratorFactory(config);
var generator = factory.createGenerator(Files.newBufferedWriter(myPath,
StandardCharsets.UTF_8));
generator.writeStartArray();
var users = generateUsers();
users.forEach(user -> {
generator.writeStartObject();
generator.write("name", user.getName());
generator.write("occupation", user.getOccupation());
generator.write("born", user.getBorn().toString());
generator.writeEnd();
});
generator.writeEnd();
generator.flush();
}
public static List<User> generateUsers() {
var born1 = LocalDate.of(1992, 3, 2);
var u1 = new User("John Doe", "gardener", born1);
var born2 = LocalDate.of(1967, 11, 22);
var u2 = new User("Brian Flemming", "teacher", born2);
var born3 = LocalDate.of(1995, 4, 7);
var u3 = new User("Lucy Black", "accountant", born3);
var born4 = LocalDate.of(1977, 10, 31);
var u4 = new User("William Bean", "pilot", born4);
return List.of(u1, u2, u3, u4);
}
}
该示例从用户列表创建users.json
文件。
var myPath = Paths.get("src/main/resources/users.json");
var config = new HashMap<String, Boolean>();
config.put(JsonGenerator.PRETTY_PRINTING, true);
var factory = Json.createGeneratorFactory(config);
var generator = factory.createGenerator(Files.newBufferedWriter(myPath,
StandardCharsets.UTF_8));
用JsonGeneratorFactory
创建一个JsonGenerator
。 工厂接收配置数据,从而可以进行漂亮的打印。
generator.writeStartArray();
数组从writeStartArray()
开始。 稍后以writeEnd()
结束。
users.forEach(user -> {
generator.writeStartObject();
generator.write("name", user.getName());
generator.write("occupation", user.getOccupation());
generator.write("born", user.getBorn().toString());
generator.writeEnd();
});
JSON 对象写在forEach
循环中。 JSON 对象以writeStartObject()
开头,以writeEnd()
结束。 键/值对使用write()
编写。
generator.flush();
使用flush()
将数据从缓冲区刷新到数据源。
在本教程中,我们已经使用 Java JSON-P 读写了 JSON 文件。 您可能也对相关教程感兴趣: Gson 教程, Java DOM 教程, Java SAX 教程和或 Java 教程。