20221115 JsonFactory、JsonParser、JsonGenerator

参考资料

概述

JsonParserJsonGeneratorJsonFactory 位于 jackson-core 模块中,此模块提供了最具底层的 Streaming JSON 解析器/生成器,这组流式 API 属于Low-Level API ,是 ObjectMapper 的底层实现

  • JsonFactory:Jackson 主要的工厂方法,用于配置和构建解析器 JsonParser 和生成器 JsonGenerator ,这个工厂实例是线程安全的,所以可以重复使用

  • JsonGenerator:用来生成 Json 格式的内容的(序列化)

  • JsonParser:读取 Json 格式的内容(反序列化)

相关概念

  • 流式(Streaming):此概念和 Java 8 中的 Stream 流是不同的。这里指的是 IO流 ,因此在读/写的最后都是需要 close

  • 增量模式(incremental mode):它表示每个部分一个一个地往上增加,类似于垒砖。使用此流式 API 读写 JSON 的方式使用的均是增量模式

  • JsonToken:每一部分都是一个独立的 Token(有不同类型的Token),最终被“拼凑”起来就是一个JSON。这是流式API里很重要的一个抽象概念。

简单使用示例

@SneakyThrows
@Test
public void testJsonGenerator() {
    JsonFactory factory = new JsonFactory();

    // 此处最终输输出到OutputStreams输出流(此处输出到文件)
    JsonGenerator jsonGenerator =
            factory.createGenerator(FileUtil.newFile("person.json"), JsonEncoding.UTF8);
    jsonGenerator.writeStartObject();   // 开始写,也就是这个符号 {

    jsonGenerator.writeStringField("name", "YourBatman");
    jsonGenerator.writeNumberField("age", 18);

    // 写入Dog对象(枚举对象)
    jsonGenerator.writeFieldName("dog");
    jsonGenerator.writeStartObject();   // {
    jsonGenerator.writeStringField("name", "旺财");
    jsonGenerator.writeStringField("color", "WHITE");
    jsonGenerator.writeEndObject();     // }

    //写入一个数组格式
    jsonGenerator.writeFieldName("hobbies"); // "hobbies" :
    jsonGenerator.writeStartArray();    // [
    jsonGenerator.writeString("篮球"); // "篮球"
    jsonGenerator.writeString("football"); // "football"
    jsonGenerator.writeEndArray();  // ]

    jsonGenerator.writeEndObject(); //结束写,也就是这个符号 }

    // 关闭IO流
    jsonGenerator.close();
}

@SneakyThrows
@Test
public void testJsonParser() {
    JsonFactory factory = new JsonFactory();

    // 此处InputStream来自于文件
    JsonParser jsonParser = factory.createParser(FileUtil.newFile("person.json"));

    // 只要还没到末尾,也就是 } 这个符号,就一直读取
    // {"name":"YourBatman","age":18,"dog":{"name":"旺财","color":"WHITE"},"hobbies":["篮球","football"]}
    JsonToken jsonToken = jsonParser.nextToken(); // token类型
    while (jsonToken != JsonToken.END_OBJECT) {
        System.out.println("1. jsonToken === " + jsonToken);
        String fieldname = jsonParser.getCurrentName();
        if ("name".equals(fieldname)) {
            jsonToken = jsonParser.nextToken();
            System.out.println("==============token类型是:" + jsonToken);
            System.out.println(jsonParser.getText());
        } else if ("age".equals(fieldname)) {
            jsonToken = jsonParser.nextToken();
            System.out.println("==============token类型是:" + jsonToken);
            System.out.println(jsonParser.getIntValue());
        } else if ("dog".equals(fieldname)) {
            jsonToken = jsonParser.nextToken();
            System.out.println("==============token类型是:" + jsonToken);
            while (jsonToken != JsonToken.END_OBJECT) {
                System.out.println("2. jsonToken === " + jsonToken);
                String dogFieldName = jsonParser.getCurrentName();
                if ("name".equals(dogFieldName)) {
                    jsonToken = jsonParser.nextToken();
                    System.out.println("======================token类型是:" + jsonToken);
                    System.out.println(jsonParser.getText());
                } else if ("color".equals(dogFieldName)) {
                    jsonToken = jsonParser.nextToken();
                    System.out.println("======================token类型是:" + jsonToken);
                    System.out.println(jsonParser.getText());
                }

                jsonToken = jsonParser.nextToken();
            }
        } else if ("hobbies".equals(fieldname)) {
            jsonToken = jsonParser.nextToken();
            System.out.println("==============token类型是:" + jsonToken);
            while (jsonParser.nextToken() != JsonToken.END_ARRAY) {
                System.out.println(jsonParser.getText());
            }
        }

        jsonToken = jsonParser.nextToken();
    }

    // 关闭IO流
    jsonParser.close();
}

person.json

{
    "name": "YourBatman",
    "age": 18,
    "dog": {
        "name": "旺财",
        "color": "WHITE"
    },
    "hobbies": [
        "篮球",
        "football"
    ]
}

JsonToken

com.fasterxml.jackson.core.JsonToken

枚举类,定义了所有的 token 类型

JsonFactory

用于创建和配置 JsonParserJsonGenerator

对 Feature 的支持包括支持判断是否启用、支持配置(同时支持判断)

  • JsonParser.FeatureJsonGenerator.Feature :支持配置

  • JsonParser.Feature :支持判断,配置的方法已弃用,推荐使用 JsonFactoryBuilder 进行配置

  • StreamReadFeatureStreamWriteFeature :支持判断不支持配置,使用 JsonFactoryBuilder 进行配置

  • JsonWriteFeatureJsonReadFeature :不支持

是否启用 Feature 的实现

内部字段:

// 默认启用的 JsonFactory.Feature
protected final static int DEFAULT_FACTORY_FEATURE_FLAGS = JsonFactory.Feature.collectDefaults();
// 默认启用的 JsonParser.Feature
protected final static int DEFAULT_PARSER_FEATURE_FLAGS = JsonParser.Feature.collectDefaults();
// 默认启用的 JsonGenerator.Feature
protected final static int DEFAULT_GENERATOR_FEATURE_FLAGS = JsonGenerator.Feature.collectDefaults();

// 当前启用的 JsonFactory.Feature
protected int _factoryFeatures = DEFAULT_FACTORY_FEATURE_FLAGS;
// 当前启用的 JsonParser.Feature
protected int _parserFeatures = DEFAULT_PARSER_FEATURE_FLAGS;
// 当前启用的 JsonGenerator.Feature
protected int _generatorFeatures = DEFAULT_GENERATOR_FEATURE_FLAGS;

这里的记录是否启用 Feature 的方法很巧妙,恰好之前在反射的代码那里看到过这种应用

参考 java.lang.reflect.Modifier

主要采用的方法是位运算,与 & 、 或 | 、非 ~

JsonFactory.Feature 的方法:

  • getMask 使用左移运算符 << 为每个枚举设置一个 mask ,用于标识

  • enabledIn 使用位运算 & 判断该 Feature 是否被启用

  • collectDefaults 使用位运算 | 计算默认启用的 Feature

JsonFactory 的方法:

  • isEnabled 类似于 JsonFactory.Feature.enabledIn

  • enable 使用位运算 |

  • disable 使用位运算 &~

ObjectMapper objectMapper = new ObjectMapper();
JsonFactory jsonFactory = objectMapper.getFactory();

int parserFeatures = jsonFactory.getParserFeatures();
System.out.println(NumberUtil.getBinaryStr(parserFeatures));        // 100000000000001

int generatorFeatures = jsonFactory.getGeneratorFeatures();
System.out.println(NumberUtil.getBinaryStr(generatorFeatures));        // 11111

二进制数字的每个位置对应枚举的 ordinal

1 对应 Feature 枚举启用,0 对应不启用

SPI 方式创建

jackson-core 包提供了 ServiceLoader 机制创建 JsonFactory 实例的方法

ServiceLoader<JsonFactory> serviceLoader = ServiceLoader.load(JsonFactory.class);
Iterator<JsonFactory> iterator = serviceLoader.iterator();
while (iterator.hasNext()) {
    System.out.println(iterator.next());
}

直接创建

JsonFactory factory = new JsonFactory();

Builder 方式创建

JsonFactory jsonFactory = new JsonFactoryBuilder().build();

JsonGenerator

提供了 write{XXX} 系列方法

从 API 中可以看出,这种 Low-Level 的 API 是只能写基本类型的:如 int、long、BigInteger… 对于对象类型如 Date、Person 等,它都是不能直接写的

写对象需要配合 ObjectCodec ,而 ObjectMapperObjectCodec 的子类

  • 使用 new JsonFactory() 创建的 JsonGenerator 是不带 ObjectCodec

  • 使用 ObjectMapper.createGenerator 创建的 JsonGenerator 是带 ObjectCodec 的,也就是 ObjectMapper 自身

JsonParser

提供了 get{XXX}Value 系列方法以及 getText

JsonFactory factory = new JsonFactory();

// 此处InputStream来自于文件
JsonParser jsonParser = factory.createParser(FileUtil.newFile("person.json"));

JsonToken jsonToken = jsonParser.nextToken();
while (jsonToken != null) {
    System.out.println(jsonToken + " :: " + jsonParser.currentName() + " :: " + jsonParser.getText());
    jsonToken = jsonParser.nextToken();
}

jsonParser.close();

输出结果

START_OBJECT :: null :: {
FIELD_NAME :: name :: name
VALUE_STRING :: name :: YourBatman
FIELD_NAME :: age :: age
VALUE_NUMBER_INT :: age :: 18
FIELD_NAME :: dog :: dog
START_OBJECT :: dog :: {
FIELD_NAME :: name :: name
VALUE_STRING :: name :: 旺财
FIELD_NAME :: color :: color
VALUE_STRING :: color :: WHITE
END_OBJECT :: dog :: }
FIELD_NAME :: hobbies :: hobbies
START_ARRAY :: hobbies :: [
VALUE_STRING :: null :: 篮球
VALUE_STRING :: null :: football
END_ARRAY :: hobbies :: ]
END_OBJECT :: null :: }

readValueAs{XXX} 系列方法需要配合 ObjectCodec 使用,同 JsonGenerator

ObjectMapper 相关

正常使用时,肯定还是用 ObjectMapper 这个门面类

ObjectMapper objectMapper = new ObjectMapper();

默认使用的 JsonFactory 实现是 MappingJsonFactory ,内部的 ObjectCodecObjectMapper

ObjectMapper 内部字段:

// 对应 JsonFactory 
protected final JsonFactory _jsonFactory;

生成 JsonGeneratorJsonParser ,配置 Feature 都是直接调用 JsonFactory 方法,ObjectMapper 只是作为门面

示例

StringReader stringReader = new StringReader("{\"a\":'1'}");

ObjectMapper objectMapper = new ObjectMapper();

// 配置 JsonParser.Feature ,和直接使用 jsonFactory 配置等效
objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);

// 获取对象
JsonFactory jsonFactory = objectMapper.getFactory();
JsonGenerator jsonGenerator = objectMapper.createGenerator(System.out);
JsonParser jsonParser = objectMapper.createParser(stringReader);

// jsonGenerator 输出
jsonGenerator.writeObject(User.newDemoUser());
System.out.println();

// jsonParser 输出
JsonToken jsonToken = jsonParser.nextToken();
while (jsonToken != null) {
    System.out.println(jsonToken + " :: " + jsonParser.currentName() + " :: " + jsonParser.getText());
    jsonToken = jsonParser.nextToken();
}

相关方法

获取对象:

  • getFactory、tokenStreamFactory

  • createGenerator

  • createParser

Feature 相关:

  • isEnabled

  • configure

  • enable

  • disable

读写 JSON:

  • readValue

  • readTree

  • writeValue

  • writeValueAsString

  • writeValueAsBytes

posted @ 2022-11-21 16:04  流星<。)#)))≦  阅读(83)  评论(0编辑  收藏  举报