流式API
是一套比较底层的API
,速度快,但是使用起来特别麻烦。它主要是有两个核心类,一个是JsonGenerator
json生成器,用来生成JSON
,另一个是JsonParser
json解析器,用来读取JSON
内容。
JsonParser 、JsonGenerator
一、引入
Jackson核心模块是所有扩展的基础。目前有3个核心模块(从Jackson 2.x开始):
Streaming:(jackson-core)定义了低级流API,包括JSON特性的实现。
Annotations:(jackson-annotations)包含标准的Jackson注解。
Databind:(jackson-databind)实现了数据绑定(和对象序列化)支持,它依赖于Streaming和Annotations包。
1.1 Jackson处理Json 的三种方式
Jackson提供了三种可选的Json处理方法:流式API(Streaming API) 、树模型(Tree Model)、数据绑定(Data Binding)。从使用角度来看,比较一下这三种处理Json的方式的特性:
Streaming API:是效率最高的处理方式(开销低、读写速度快,但程序编写复杂度高)
Tree Model:是最灵活的处理方式 ObjectMapper 生成树,树组成 JsonNode 节点集
Data Binding:是最常用的处理方式(简单数据绑定,是指从Java Map、List、String、Numbers、Boolean和空值进行转换;完整数据绑定,是指从任何Java bean类型 (及上文所述的”简单”类型) 进行转换)
1.2 流式API
流式API
是一套比较底层的API
,速度快,但是使用起来特别麻烦。它主要是有两个核心类,一个是JsonGenerator
json生成器,用来生成JSON
,另一个是JsonParser
json解析器,用来读取JSON
内容。
二、 JsonParser详解
2.1 简介
1、与Java8的“流式”概念不同,这种Jackson的这种流式是属于IO流,在写出与读入的最后都要进行流的关闭 —— close()。
2、这种流式API(Streaming APIs),是一种高性能(high-performance)读写JSON的方式,同时也是一种增量模式(incremental mode)。
3、Token概念:使用流式API的时候,每一个JSON 字符串都是一个独立的 token ,每一个token都会被增量处理(可以理解为一个一个地往上增加,类似于垒砖),这就是“增量模式”的含义。比如:
1 | { |
4、流式API的缺点:虽然流式API在性能上有所特长,但是通过第三点,也可以知道,每一个token都是增量处理的,也就是说,我们必须要小心翼翼地处理每个token,这可能会因为粗心导致丢掉必要的token (如 “}”、”]” 等),而且代码可能并不简洁,可读性也不一定好,因此,不到需要考虑性能的时候,一定不要使用这种方式。
2.2、流数据处理设计模式
2.2.1push, stream-based, 事件驱动。代表SAX(JSR 5)
2.2.2 pull, stream-based,事件驱动。代表StAX, Jackson, opencsv
游标模式
输入 | 输出 | |
---|---|---|
StAX(JSR 173) | javax.xml.stream.XMLStreamReader l 获取游标当前的数据: int getEventType(), getXXX(), hasXXX(), isXXX() l 移动游标: public int next() throws XMLStreamException public int nextTag() throws XMLStreamException l 判断终止状态: public boolean hasNext() throws XMLStreamException l 状态常量: javax.xml.stream.XMLStreamConstants |
javax.xml.stream.XMLStreamWriter l 移动游标: wirteXXX() |
Jackson | com.fasterxml.jackson.core.JsonParser l 获取游标当前的数据: getXXX() l 移动游标: nextXXX() l 判断终止状态: nextXXX() == null l 状态常量: com.fasterxml.jackson.core.JsonToken |
com.fasterxml.jackson.core.JsonGenerator l 移动游标: wirteXXX() |
JSON-P (JSR 353) | javax.json.stream.JsonParser l 获取游标当前的数据: getXXX() l 移动游标: public JsonParser.Event next() l 判断终止状态: public boolean hasNext() l 状态常量: javax.json.stream.JsonParser.Event |
javax.json.stream.JsonGenerator l 移动游标: wirteXXX() |
迭代器模式
输入 | 输出 | |
---|---|---|
StAX(JSR 173) | javax.xml.stream.XMLEventReader l 迭代方法: public XMLEvent nextEvent() throws XMLStreamException public XMLEvent nextTag() throws XMLStreamException l 判断终止状态: public boolean hasNext() l 迭代对象: javax.xml.stream.events.XMLEvent |
javax.xml.stream.XMLEventWriter public void add(XMLEvent) throws XMLStreamException |
opencsv | com.opencsv.CSVReader l 迭代方法: public String[] readNext() throws IOException protected String getNextLine() throws IOException l 判断终止状态: readNext() == null l 迭代对象: String[] |
com.opencsv.CSVWriter public void writeNext(String[]) |
2.2.3 内存对象模型。代表DOM(JSR 5), JSON-P(JSR 353)
比较:
内存对象模型模式灵活性高,可以对数据自由访问。代价是占用内存和CPU大。in memory模式适合小规模数据。
stream-based模式,对数据的输入、解析和输出是单向、串行且实时的,不需要对数据进行准确的预知。stream-based模式下,输入的数据被使用后会立即被丢弃,因此,stream-based模式占用内存和CPU小。代价是,在数据处理过程中的特定的时刻,只能看到一个局部的信息。
push模式的解析器,会将处理的数据发送(push)给客户端,不管客户端是否准备好使用这些数据,控制权在解析器。
pull模式的解析器,会等待客户端的调用,客户端只在需要的时候,通过调用解析器的方法来获取(pull)数据,控制权在客户端。
2.3 使用
2.3.1 构造对象
定义用于读取JSON内容的公共API的基类。实例是使用实例的工厂方法创建的JsonFactory
1 | JsonFactory factory = new JsonFactory(); |
2.3.2 样例
1 | String carJson = "{\"name\": \"中国\",\"provinces\": [" |
2.3方法分析
2.3.1 JsonToken
1 | JsonToken jsonToken = parser.nextToken(); |
| token0 token1 token2 token3 游标起始,getText(),getValueAsString(),getCurrentName() 都是null,点击nextnextToken()
token0 | token1 token2 token3 getText() token0(可以是{,[等) getValueAsString() token0非{[
token0 token1 token2 token3**|** 可以获取到token3 结束
2.3.2 getCurrentName()
获取当前token的key(如果把json堪称K:V)
(1)、对于JsonToken是FIELD_NAME类型,getText(),getValueAsString(),getCurrentName()三者一样;
(2)、对于 字段值(value),getCurrentName()为key;
(3)、对于 字段(key),getCurrentName()为key;
(3)、对于其他(数组值,START_OBJECT,END_OBJECT)getCurrentName()为null。
2.3.3 getText(),getValueAsString()的区别与联系
两者都是获取当前token值,getText() 任意JsonToken,getValueAsString()不支持(START_OBJECT,END_OBJECT,START_ARRAY,END_ARRAY),
三、JsonGenerator
Jackson JsonGenerator用于从Java对象(或代码从中生成JSON的任何数据结构)生成JSON。
3.1、创建一个JsonGenerator
为了创建Jackson JsonGenerator,必须首先创建JsonFactory实例。 这是创建JsonFactory的方法:
1 | JsonFactory factory = new JsonFactory(); |
一旦创建了JsonFactory,就可以使用JsonFactory的createGenerator()方法创建JsonGenerator。 这是创建JsonGenerator的示例:
1 | JsonFactory factory = new JsonFactory(); |
createGenerator()方法的第一个参数是生成的JSON的目标。 在上面的示例中,参数是File对象。 这意味着生成的JSON将被写入给定文件。 createGenerator()方法已重载,因此还有其他版本的createGenerator()方法采用例如OutputStream等,提供了有关将生成的JSON写入何处的不同选项。
createGenerator()方法的第二个参数是生成JSON时使用的字符编码。 上面的示例使用UTF-8。
3.2、使用JsonGenerator生成JSON
一旦创建了JsonGenerator,就可以开始生成JSON。 JsonGenerator包含一组write …()方法,可以使用这些方法来编写JSON对象的各个部分。 这是一个使用Jackson JsonGenerator生成JSON的简单示例:
1 | JsonFactory factory = new JsonFactory(); |
此示例首先调用writeStartObject(),将{写入输出。 然后,该示例调用writeStringField(),将品牌字段名称+值写入输出。 之后,将调用writeNumberField()方法,此方法会将Doors字段名称+值写入输出。 最后,调用writeEndObject(),将}写入输出。
JsonGenerator还可以使用许多其他写入方法。 这个例子只显示了其中一些。
3.3、关闭JsonGenerator
完成生成JSON后,应关闭JsonGenerator。 您可以通过调用其close()方法来实现。 这是关闭JsonGenerator的样子:
1 | generator.close(); |
四、引用
1 | https://blog.csdn.net/u014745069/article/details/88920056?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.edu_weight&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.edu_weight |
- 本文作者: 初心
- 本文链接: http://funzzz.fun/2021/01/04/jackson---2JsonParser/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!