有道无术,术尚可求,有术无道,止于术。
本系列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. 创建 JsonParserJsonFactory 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 */@Deprecatedpublic JsonFactory getJsonFactory() {return this.getFactory();}public JsonFactory getFactory() {return this.getJsonFactory();}
}
我们自定义一个StudyObjectCodec,这里只实现readValue(JsonParser jsonParser, Class<T> aClass)方法,也只解析了User的几个属性,因为解析比生成复杂的多,这里只是简单演示:
public class StudyObjectCodec extends ObjectCodec {// 省略其他实现@Overridepublic <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. 创建 JsonParserJsonFactory 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}