Contents

Jackson 流API

1 . 概述

在本文中,我们将研究 Jackson Streaming API。它支持读写,通过使用它,我们可以编写高性能、快速的 JSON 解析器。 另一方面,它有点难以使用——JSON 数据的每个细节都需要在代码中明确处理。

2. Maven依赖

首先,我们需要向jackson-core 添加一个 Maven 依赖项:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.11.1</version>
</dependency>

3. 写入 JSON

我们可以使用*JsonGenerator 类将 JSON 内容直接写入OutputStream* 。首先,我们需要创建该对象的实例:

ByteArrayOutputStream stream = new ByteArrayOutputStream();
JsonFactory jfactory = new JsonFactory();
JsonGenerator jGenerator = jfactory
  .createGenerator(stream, JsonEncoding.UTF8);

接下来,假设我们要编写具有以下结构的 JSON:

{  
   "name":"Tom",
   "age":25,
   "address":[  
      "Poland",
      "5th avenue"
   ]
}

我们可以使用JsonGenerator的实例将特定字段直接写入OutputStream

jGenerator.writeStartObject();
jGenerator.writeStringField("name", "Tom");
jGenerator.writeNumberField("age", 25);
jGenerator.writeFieldName("address");
jGenerator.writeStartArray();
jGenerator.writeString("Poland");
jGenerator.writeString("5th avenue");
jGenerator.writeEndArray();
jGenerator.writeEndObject();
jGenerator.close();

要检查是否创建了正确的 JSON,我们可以创建一个包含 JSON 对象的String对象:

String json = new String(stream.toByteArray(), "UTF-8");
assertEquals(
  json, 
  "{\"name\":\"Tom\",\"age\":25,\"address\":[\"Poland\",\"5th avenue\"]}");

4.解析JSON

当我们得到一个 JSON字符串作为输入,并且我们想从中提取特定字段时,可以使用*JsonParser *类:

String json
  = "{\"name\":\"Tom\",\"age\":25,\"address\":[\"Poland\",\"5th avenue\"]}";
JsonFactory jfactory = new JsonFactory();
JsonParser jParser = jfactory.createParser(json);
String parsedName = null;
Integer parsedAge = null;
List<String> addresses = new LinkedList<>();

我们想从输入的 JSON中获取parsedNameparsedAgeaddresses字段。为此,我们需要处理底层的解析逻辑并自己实现:

while (jParser.nextToken() != JsonToken.END_OBJECT) {
    String fieldname = jParser.getCurrentName();
    if ("name".equals(fieldname)) {
        jParser.nextToken();
        parsedName = jParser.getText();
    }
    if ("age".equals(fieldname)) {
        jParser.nextToken();
        parsedAge = jParser.getIntValue();
    }
    if ("address".equals(fieldname)) {
        jParser.nextToken();
        while (jParser.nextToken() != JsonToken.END_ARRAY) {
            addresses.add(jParser.getText());
        }
    }
}
jParser.close();

根据字段名称,我们将其提取并分配给适当的字段。解析文档后,所有字段都应该有正确的数据:

assertEquals(parsedName, "Tom");
assertEquals(parsedAge, (Integer) 25);
assertEquals(addresses, Arrays.asList("Poland", "5th avenue"));

5. 提取 JSON 部分

有时,当我们解析 JSON 文档时,我们只对一个特定字段感兴趣。 理想情况下,在这些情况下,我们只想解析文档的开头,一旦找到需要的字段,我们就可以中止处理。 假设我们只对输入 JSON的*年龄字段感兴趣。*在这种情况下,我们可以实现解析逻辑,一旦找到需要的字段就停止解析:

while (jParser.nextToken() != JsonToken.END_OBJECT) {
    String fieldname = jParser.getCurrentName();
    if ("age".equals(fieldname)) {
        jParser.nextToken();
        parsedAge = jParser.getIntValue();
        return;
    }
}
jParser.close();

处理后,唯一的parsedAge字段将有一个值:

assertNull(parsedName);
assertEquals(parsedAge, (Integer) 25);
assertTrue(addresses.isEmpty());

多亏了这一点,JSON 文档的解析会快很多,因为我们不需要读取整个文档,只需要读取其中的一小部分。