版本约定
- Jackson版本:2.11.0
- Spring Framework版本:5.2.6.RELEASE
- Spring Boot版本:2.3.0.RELEASE
小贴士:截止到本文,本系列前面所有示例都只仅仅导入jackson-core而已,后续若要新增jar包我会额外说明,否则相同
正文
什么叫读JSON?就是把一个JSON 字符串 解析为对象or树模型嘛,因此也称作解析JSON串。Jackson底层流式API使用JsonParser来完成JSON字符串的解析。
最简使用Demo
准备一个POJO:
@Data public class Person { private String name; private Integer age; }
测试用例:把一个JSON字符串绑定(封装)进一个POJO对象里
@Test public void test1() throws IOException { String jsonStr = "{\"name\":\"YourBatman\",\"age\":18}"; Person person = new Person(); JsonFactory factory = new JsonFactory(); try (JsonParser jsonParser = factory.createParser(jsonStr)) { // 只要还没结束"}",就一直读 while (jsonParser.nextToken() != JsonToken.END_OBJECT) { String fieldname = jsonParser.getCurrentName(); if ("name".equals(fieldname)) { jsonParser.nextToken(); person.setName(jsonParser.getText()); } else if ("age".equals(fieldname)) { jsonParser.nextToken(); person.setAge(jsonParser.getIntValue()); } } System.out.println(person); } }
运行程序,输出:
Person(name=YourBatman, age=18)
成功把一个JSON字符串的值解析到Person对象。你可能会疑问,怎么这么麻烦?那当然,这是底层流式API,纯手动档嘛。你获得了性能,可不要失去一些便捷性嘛。
小贴士:底层流式API一般面向“专业人士”,应用级开发使用高阶API ObjectMapper即可。当然,读完本系列就能让你完全具备“专业人士”的实力😄
JsonParser针对不同的value类型,提供了非常多的方法用于实际值的获取。
直接值获取:
// 获取字符串类型 public abstract String getText() throws IOException; // 数字Number类型值 标量值(支持的Number类型参照NumberType枚举) public abstract Number getNumberValue() throws IOException; public enum NumberType { INT, LONG, BIG_INTEGER, FLOAT, DOUBLE, BIG_DECIMAL }; public abstract int getIntValue() throws IOException; public abstract long getLongValue() throws IOException; ... public abstract byte[] getBinaryValue(Base64Variant bv) throws IOException;
这类方法可能会抛出异常:比如value值本不是数字但你调用了getInValue()方法~
小贴士:如果value值是null,像getIntValue()、getBooleanValue()等这种直接获取方法是会抛出异常的,但getText()不会
带默认值的值获取,具有更好安全性:
public String getValueAsString() throws IOException { return getValueAsString(null); } public abstract String getValueAsString(String def) throws IOException; ... public long getValueAsLong() throws IOException { return getValueAsLong(0); } public abstract long getValueAsLong(long def) throws IOException; ...
此类方法若碰到数据的转换失败时,不会抛出异常,把def
作为默认值返回。
组合方法
同JsonGenerator
一样,JsonParser也提供了高钙片组合方法,让你更加便捷的使用。
自动绑定
听起来像高级功能,是的,它必须依赖于ObjectCodec
去实现,因为实际是全部委托给了它去完成的,也就是我们最为熟悉的readXXX系列方法:
我们知道,ObjectMapper就是一个ObjectCodec,它属于高级API,本文显然不会用到ObjectMapper它喽,因此我们自己手敲一个实现来完成此功能。
自定义一个ObjectCodec,Person类专用:用于把JSON串自动绑定到实例属性。
public class PersonObjectCodec extends ObjectCodec { ... @SneakyThrows @Override public <T> T readValue(JsonParser jsonParser, Class<T> valueType) throws IOException { Person person = (Person) valueType.newInstance(); // 只要还没结束"}",就一直读 while (jsonParser.nextToken() != JsonToken.END_OBJECT) { String fieldname = jsonParser.getCurrentName(); if ("name".equals(fieldname)) { jsonParser.nextToken(); person.setName(jsonParser.getText()); } else if ("age".equals(fieldname)) { jsonParser.nextToken(); person.setAge(jsonParser.getIntValue()); } } return (T) person; } ... }
有了它,就可以实现我们的自动绑定了,书写测试用例:
@Test public void test3() throws IOException { String jsonStr = "{\"name\":\"YourBatman\",\"age\":18, \"pickName\":null}"; JsonFactory factory = new JsonFactory(); try (JsonParser jsonParser = factory.createParser(jsonStr)) { jsonParser.setCodec(new PersonObjectCodec()); System.out.println(jsonParser.readValueAs(Person.class)); } }
运行程序,输出:
Person(name=YourBatman, age=18)
这就是ObjectMapper自动绑定的核心原理所在,其它更为强大能力将在后续章节详细展开。
JsonToken
在上例解析过程中,有一个非常重要的角色,那便是:JsonToken。它表示解析JSON内容时,用于返回结果的基本标记类型的枚举。
public enum JsonToken { NOT_AVAILABLE(null, JsonTokenId.ID_NOT_AVAILABLE), START_OBJECT("{", JsonTokenId.ID_START_OBJECT), END_OBJECT("}", JsonTokenId.ID_END_OBJECT), START_ARRAY("[", JsonTokenId.ID_START_ARRAY), END_ARRAY("]", JsonTokenId.ID_END_ARRAY), // 属性名(key) FIELD_NAME(null, JsonTokenId.ID_FIELD_NAME), // 值(value) VALUE_EMBEDDED_OBJECT(null, JsonTokenId.ID_EMBEDDED_OBJECT), VALUE_STRING(null, JsonTokenId.ID_STRING), VALUE_NUMBER_INT(null, JsonTokenId.ID_NUMBER_INT), VALUE_NUMBER_FLOAT(null, JsonTokenId.ID_NUMBER_FLOAT), VALUE_TRUE("true", JsonTokenId.ID_TRUE), VALUE_FALSE("false", JsonTokenId.ID_FALSE), VALUE_NULL("null", JsonTokenId.ID_NULL), }
为了辅助理解,A哥用一个例子,输出各个部分一目了然:
@Test public void test2() throws IOException { String jsonStr = "{\"name\":\"YourBatman\",\"age\":18, \"pickName\":null}"; System.out.println(jsonStr); JsonFactory factory = new JsonFactory(); try (JsonParser jsonParser = factory.createParser(jsonStr)) { while (true) { JsonToken token = jsonParser.nextToken(); System.out.println(token + " -> 值为:" + jsonParser.getValueAsString()); if (token == JsonToken.END_OBJECT) { break; } } } }
运行程序,输出
{"name":"YourBatman","age":18, "pickName":null} START_OBJECT -> 值为:null FIELD_NAME -> 值为:name VALUE_STRING -> 值为:YourBatman FIELD_NAME -> 值为:age VALUE_NUMBER_INT -> 值为:18 FIELD_NAME -> 值为:pickName VALUE_NULL -> 值为:null END_OBJECT -> 值为:null
从左至右解析,一一对应。各个部分用下面这张图可以简略表示出来:
小贴士:解析时请确保你的的JSON串是合法的,否则抛出JsonParseException
异常