# Java JSON 处理教程

原文：http://zetcode.com/java/jsonp/

Java JSON 处理教程展示了如何使用 JSON-P 库来处理 JSON。 这些示例将 Java 对象写入 JSON 文件，并将 JSON 数据读取到 Java 对象。 在作者的 Github [仓库](https://github.com/janbodnar/Java-Advanced/tree/master/json/jsonp)中提供了代码示例。

## 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 创建我们的应用。

```java
<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`

```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 字符串被打印到控制台。

```java
var json = Json.createObjectBuilder()
    .add("name", "John Doe")
    .add("occupation", "gardener")
    .add("born", born).build();

```

用`createObjectBuilder()`创建一个`JsonObjectBuilder`。 新的对将插入`add()`。 最后，使用`build()`结束字符串。

```java
var result = json.toString();

```

我们使用`toString()`将`JsonObject`转换为字符串。

```java
{"name":"John Doe","occupation":"gardener","born":"1992-03-02"}

```

这是输出。

## `PRETTY_PRINTING`

通过`JsonGenerator.PRETTY_PRINTING`配置设置，我们可以设置写入器进行漂亮的打印。

`JsonPrettyPrintEx.java`

```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 对象并将其打印到控制台。 输出打印精美。

```java
var config = new HashMap<String, Boolean>();
config.put(JsonGenerator.PRETTY_PRINTING, true);

var jwf = Json.createWriterFactory(config);

```

配置文件被传递到`JsonWriterFactory`。

```java
{
    "name": "John Doe",
    "occupation": "gardener",
    "born": "1992-03-02"
}

```

这是输出。

## JSON-P `JsonArrayBuilder`

`JsonArrayBuilder`是用于创建和修改`JsonArray`对象的构建器。

`JsonArrayBuilderEx.java`

```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`。

```java
var ab = Json.createArrayBuilder();

```

用`createArrayBuilder()`创建一个`JsonArrayBuilder`。

```java
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 对象并将其添加到构建器中。

```java
var jsonArray = ab.build();

```

`build()`方法从构建器创建`JsonArray`。

```java
jsonWriter.writeArray(jsonArray);

```

`JsonArray`被写入写入器。

```java
[
    {
        "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`

```java
[
  {
    "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`

```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`文件。

```java
var is = new FileInputStream("src/main/resources/users.json");

var factory = Json.createParserFactory(null);
var parser = factory.createParser(is, StandardCharsets.UTF_8);

```

从`JsonParserFactory`创建一个`JsonParser`。

```java
if (!parser.hasNext() && parser.next() != JsonParser.Event.START_ARRAY) {

    return;
}

```

首先，我们传递数组的开头。

```java
// looping over object attributes
while (parser.hasNext()) {

    var event = parser.next();

    // starting object
    if (event == JsonParser.Event.START_OBJECT) {
...        

```

然后，我们在`while`循环中遍历数组。 当我们到达数组末尾时，解析器的`hasNext()`方法返回`false`。 我们使用`next()`拉下一个解析事件。

```java
while (parser.hasNext()) {

    event = parser.next();

    if (event == JsonParser.Event.KEY_NAME) {
...

```

在另一个`while`循环中，我们遍历当前对象的键。

```java
var key = parser.getString();

switch (key) {

    case "name":
        parser.next();

        System.out.printf("Name: %s%n", parser.getString());
        break;
...        

```

在`switch`语句中，我们检查键名称，并通过`getString()`获得其值。

```java
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`

```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`

```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`文件。

```java
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`。 工厂接收配置数据，从而可以进行漂亮的打印。

```java
generator.writeStartArray();

```

数组从`writeStartArray()`开始。 稍后以`writeEnd()`结束。

```java
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()`编写。

```java
generator.flush();

```

使用`flush()`将数据从缓冲区刷新到数据源。

在本教程中，我们已经使用 Java JSON-P 读写了 JSON 文件。 您可能也对相关教程感兴趣： [Gson 教程](/java/gson/)， [Java DOM 教程](/java/dom/)， [Java SAX 教程](/java/sax/)和或 [Java 教程](/lang/java/)。