有道无术,术尚可求,有术无道,止于术。
本系列Jackson 版本 2.17.0
源码地址:https://gitee.com/pearl-organization/study-seata-demo
文章目录
- 1. 前言
- 2. 解析原理
- 3. 案例演示
- 3.1 创建 JsonParser
- 3.2 解析
- 3.3 读取
- 3.4 测试
1. 前言
在上一篇文档中,我们使用JsonGenerator
生成了一个JSON
文件,接下来我们学习使用JsonParser
进行解析。
2. 解析原理
JsonParser
进行解析的大致流程如下:
- 从头开始扫描
JSON
字符串 - 依次识别每个
JSON
组成元素 - 解析到结束位置,关闭解析器
JSON
格式是非常标准的,JsonParser
会从头到尾识别每一个组成元素,比如识别到对象开始符号{
时,会生成一个对应JsonToken
令牌对象,其中包含了元素标识START_OBJECT
。
JsonToken
对象是一个枚举类,用于判断解析元素的类型:
public enum JsonToken {
// 当前无法返回
NOT_AVAILABLE((String)null, -1),
// 对象开始符号:{
START_OBJECT("{", 1),
// 对象结束符号:}
END_OBJECT("}", 2),
// 数组开始符号
START_ARRAY("[", 3),
// 数组结束符号
END_ARRAY("]", 4),
// 当时是属性名称
FIELD_NAME((String)null, 5),
// 嵌入对象
VALUE_EMBEDDED_OBJECT((String)null, 12),
// 字符串类型值
VALUE_STRING((String)null, 6),
// INT类型值
VALUE_NUMBER_INT((String)null, 7),
// FLOAT类型值
VALUE_NUMBER_FLOAT((String)null, 8),
// True 类型值
VALUE_TRUE("true", 9),
// False 类型值
VALUE_FALSE("false", 10),
// null 值
VALUE_NULL("null", 11);
}
3. 案例演示
演示需求: 将之前生成的JSON
文件反序列化为User
对象。
3.1 创建 JsonParser
JsonParser
是读取JSON
内容API
的基类,它有很多实现子类:
其实例也是由JsonFactory
创建,JsonFactory
提供了多种创建方法:
public abstract JsonParser createParser(byte[] data) throws IOException;
public abstract JsonParser createParser(byte[] data, int offset, int len) throws IOException;
public abstract JsonParser createParser(char[] content) throws IOException;
public abstract JsonParser createParser(char[] content, int offset, int len) throws IOException;
public abstract JsonParser createParser(DataInput in) throws IOException;
public abstract JsonParser createParser(File f) throws IOException;
public abstract JsonParser createParser(InputStream in) throws IOException;
public abstract JsonParser createParser(Reader r) throws IOException;
public abstract JsonParser createParser(String content) throws IOException;
public abstract JsonParser createParser(URL url) throws IOException;
这里我们直接通过文件对象创建:
// 1. 创建 JsonParser
JsonFactory jsonFactory = JsonFactory.builder().build();
File file = new File("E:\\TD\\pearl\\study-jackson-demo\\jackson-core-demo\\src\\main\\java\\com\\pearl\\jacksoncore\\demo\\file\\user.json");
JsonParser jsonParser = jsonFactory.createParser(file);
上面创建的JsonParser
实例类型是UTF8StreamJsonParser
:
3.2 解析
JsonParser
提供了isClosed()
方法判断是否关闭,nextToken()
方法解析下一个元素,使用这两个方法循环解析JSON
的所有元素:
while (!jsonParser.isClosed()) {
JsonToken jsonToken = jsonParser.nextToken();
System.out.println("当前解析到的令牌类型:" + jsonToken);
}
所有元素类型如下:
当前解析到的令牌类型:START_OBJECT
当前解析到的令牌类型:FIELD_NAME
当前解析到的令牌类型:VALUE_NUMBER_INT
当前解析到的令牌类型:FIELD_NAME
当前解析到的令牌类型:VALUE_STRING
当前解析到的令牌类型:FIELD_NAME
当前解析到的令牌类型:VALUE_NUMBER_INT
当前解析到的令牌类型:FIELD_NAME
当前解析到的令牌类型:START_OBJECT
当前解析到的令牌类型:FIELD_NAME
当前解析到的令牌类型:VALUE_NUMBER_INT
3.3 读取
JsonParser
提供了多个将JSON
解析为对象或树模型的方法:
查看readValueAs
方法,可以看到实际是调用ObjectCodec
对象的读取方法:
public <T> T readValueAs(Class<T> valueType) throws IOException {
return this._codec().readValue(this, valueType);
}
protected ObjectCodec _codec() {
ObjectCodec c = this.getCodec();
if (c == null) {
throw new IllegalStateException("No ObjectCodec defined for parser, needed for deserialization");
} else {
return c;
}
}
ObjectCodec
是一个抽象类,定义了JsonParser
和JsonGenerator
用于序列化和反序列化POJO
对象的正则表达式,其标准实现为jackson-databind
模块中的ObjectMapper
类。ObjectCodec
是非常重要的一个类,JSON
和POJO
转换的规则和逻辑需要实现该抽象类。
ObjectCodec
中可以看到定义了很多读写方法,同时它继承了TreeCodec
抽象类,说明也具备读取为树模型的能力:
public abstract class ObjectCodec extends TreeCodec implements Versioned {
public abstract Version version();
public abstract <T> T readValue(JsonParser var1, Class<T> var2) throws IOException;
public abstract <T> T readValue(JsonParser var1, TypeReference<T> var2) throws IOException;
public abstract <T> T readValue(JsonParser var1, ResolvedType var2) throws IOException;
public abstract <T> Iterator<T> readValues(JsonParser var1, Class<T> var2) throws IOException;
public abstract <T> Iterator<T> readValues(JsonParser var1, TypeReference<T> var2) throws IOException;
public abstract <T> Iterator<T> readValues(JsonParser var1, ResolvedType var2) throws IOException;
public abstract void writeValue(JsonGenerator var1, Object var2) throws IOException;
public abstract <T extends TreeNode> T readTree(JsonParser var1) throws IOException;
public abstract void writeTree(JsonGenerator var1, TreeNode var2) throws IOException;
public abstract TreeNode createObjectNode();
public abstract TreeNode createArrayNode();
public abstract JsonParser treeAsTokens(TreeNode var1);
public abstract <T> T treeToValue(TreeNode var1, Class<T> var2) throws JsonProcessingException;
/** @deprecated */
@Deprecated
public JsonFactory getJsonFactory() {
return this.getFactory();
}
public JsonFactory getFactory() {
return this.getJsonFactory();
}
}
我们自定义一个StudyObjectCodec
,这里只实现readValue(JsonParser jsonParser, Class<T> aClass)
方法,也只解析了User
的几个属性,因为解析比生成复杂的多,这里只是简单演示:
public class StudyObjectCodec extends ObjectCodec {
// 省略其他实现
@Override
public <T> T readValue(JsonParser jsonParser, Class<T> aClass) throws IOException {
// 1. 创建用户对象
User user = new User();
// 2. 循环解析每一个元素
while (!jsonParser.isClosed()) {
// 解析到下一个元素
JsonToken jsonToken = jsonParser.nextToken();
System.out.println("当前解析到的令牌类型:" + jsonToken);
// 2.1 如果是属性名称类型
if (JsonToken.FIELD_NAME.equals(jsonToken)) {
String currentName = jsonParser.currentName(); // 获取属性名
System.out.println("属性名称:" + currentName);
if ("id".equals(currentName) ) {
jsonParser.nextToken(); // 解析到下一个元素,即为属性对应的值
Long userId = jsonParser.getLongValue();
user.setId(userId);
}
if ("name".equals(currentName)) {
jsonParser.nextToken();
String userName = jsonParser.getValueAsString();
user.setName(userName);
}
if ("age".equals(currentName)) {
jsonParser.nextToken();
int age = jsonParser.getIntValue();
user.setAge(age);
}
}
}
// 3. 返回
return (T) user;
}
最后设置ObjectCodec
,完整代码如下:
public class JsonParserDemo {
public static void main(String[] args) throws IOException {
// 1. 创建 JsonParser
JsonFactory jsonFactory = JsonFactory.builder().build();
File file = new File("E:\\TD\\pearl\\study-jackson-demo\\jackson-core-demo\\src\\main\\java\\com\\pearl\\jacksoncore\\demo\\file\\user.json");
JsonParser jsonParser = jsonFactory.createParser(file);
// 2. 反序列化
jsonParser.setCodec(new StudyObjectCodec());
User user = jsonParser.readValueAs(User.class);
System.out.println(user);
}
}
3.4 测试
运行测试案例,查看控制台:
User{id=1701893746586685440, name='坤坤', age=18, org=null, roleList=null}