Java 中动态 JSON 对象的使用
最主流的 JSON 处理库是 fasterxml 的
Jaskson
和 google 的Gson
等。(其他的还有比如com.alibaba:fastjson
或net.sf.json-lib:json-lib
等)
在已有实体类结构的情况下,现有的 JSON 库可以轻松地把 JSON 文本反序列为实体类。
// Jackson 序列化
com.fasterxml.jackson.databind.ObjectMapper#writeValueAsString
// Jackson 反序列化
com.fasterxml.jackson.databind.ObjectMapper#readValue(java.lang.String, java.lang.Class<T>)
// Gson 序列化
com.google.gson.Gson#toJson(java.lang.Object)
// Gson 反序列化
com.google.gson.Gson#fromJson(java.lang.String, java.lang.Class<T>)
但是如果未知实体类的结构,那么一般操作方式就是直接把 JSON 文本转成java.util.Map
,或者JSON 库本身的JSON对象模型。
一、Jackson
1. 基本模型
Jaskson
的动态JSON对象模型如下图所示:
顶层是TreeNode
和JsonNode
,其可直接使用的子类主要分为两种,分别是ContainerNode
和ValueNode
:
- 其中
ValueNode
的众多子类是 JSON 中的各种值类型,例如某个key的value是一个字符串(TextNode
)、或者整型(IntNode
)、或者null(NullNode
)。或者一个单独的值也是符合 JSON 结构规范的。 - 而
ContainerNode
则是最常见的 JSON 结构了,主要分为ObjectNode
和ArrayNode
,分别对应两个顶层结构:花括号({}
)与方括号([]
)。
使用方法:
- 使用
com.fasterxml.jackson.databind.ObjectMapper#readTree(java.lang.String)
方法把 JSON 文本解析成JsonNode
对象。当然这个方法还有其他重载可以接受不同参数,此处不再赘述。 - 使用
com.fasterxml.jackson.databind.node.JsonNodeFactory#*Node
方法可以创建各种 Node 对象。ArrayNode/ObjectNode/ObjectMapper 也可以创建各种 Node 对象,是通过调用其内部的JsonNodeFactory实例完成的。
2. 示例
以如下的 JSON 文本举例:
[
{
"name": "zhangsan",
"age": 24
},
{
"name": "lisi",
"age": 30
}
]
先在项目的Gradle文件中导入依赖:
implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.0-rc2'
引入
jackson-databind
即可,jackson-databind
会自己引入对应的jackson-core
和jackson-annotations
。
然后直接上代码片段:
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.IntNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
public class JacksonTest {
/**
* <pre> json:
* [
* {
* "name": "zhangsan",
* "age": 24
* },
* {
* "name": "lisi",
* "age": 30
* }
* ]
* </pre>
*/
private static final String json = "[{\"name\": \"zhangsan\",\"age\": 24},{\"name\": \"lisi\",\"age\": 30}]";
private static ObjectMapper objectMapper = new ObjectMapper();
public static void main(String[] args) {
JsonNode jsonNode = null;
try {
// 把 JSON 文本解析成 JsonNode 对象
jsonNode = objectMapper.readTree(json);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
// 该 JSON 文本最顶层的 JSON 模型是一个 ArrayNode
ArrayNode arrayNode = (ArrayNode) jsonNode;
// ArrayNode 的第一项是一个 ObjectNode
ObjectNode objectNode = (ObjectNode) arrayNode.get(0);
// 该 objectNode 中 key 为 "name" 的值
TextNode name = (TextNode) objectNode.get("name");
// 该 objectNode 中 key 为 "age" 的值
IntNode age = (IntNode) objectNode.get("age");
// 往 ObjectNode 中添加键值对,或者修改 value
objectNode.put("city", "beijing");
objectNode.put("age", 25);
// 往 ArrayNode 中删除一项,或者添加一项
arrayNode.remove(1);
arrayNode.add("a new item");
// JsonNodeFactory.instance.*Node 方法可以创建各种 Node 对象
arrayNode.add(JsonNodeFactory.instance.nullNode());
// 直接 print 可以打印 JSON 文本
System.out.println(jsonNode);
// ArrayNode/ObjectNode/ObjectMapper 也可以创建各种 Node 对象
TextNode textNode1 = arrayNode.textNode("test");
ArrayNode arrayNode1 = objectMapper.createArrayNode();
System.out.println(textNode1);
}
}
参考:
https://www.baeldung.com/jackson-mapping-dynamic-object
https://www.baeldung.com/jackson-json-node-tree-model
二、Gson
1. 基本模型
相比Jackson
,Gson
的动态JSON对象模型就比较简洁:
- 顶层是
JsonElement
,其可直接使用的子类主要分为四种:JsonObject
、JsonArray
、JsonNull
、JsonPrimitive
。前三个可以从字面理解,JsonPrimitive
则是各种基本值类型,大概类似于 Jackson 的ValueNode
除去NullNode
。
注意
gson
的com.google.gson.JsonObject
与json-lib
的net.sf.json.JSONObject
和fastjson
的com.alibaba.fastjson.JSONObject
区分一下,不要用混了。
使用方法:
- 使用
com.google.gson.JsonParser#parseString
方法把 JSON 文本解析成JsonElement
对象。当然这个方法还有其他类似的比如parseReader
,此处不再赘述。 JsonElement
的各个子类都可以直接new
出来,其中JsonNull
则推荐使用JsonNull.INSTANCE
。
2. 示例
依旧以上面的 JSON 文本举例,先在项目的Gradle文件中导入依赖:
implementation 'com.google.code.gson:gson:2.8.6'
然后直接上代码片段:
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;
public class GsonTest {
/**
* <pre> json:
* [
* {
* "name": "zhangsan",
* "age": 24
* },
* {
* "name": "lisi",
* "age": 30
* }
* ]
* </pre>
*/
private static final String json = "[{\"name\": \"zhangsan\",\"age\": 24},{\"name\": \"lisi\",\"age\": 30}]";
public static void main(String[] args) {
// 把 JSON 文本解析成 JsonElement 对象
JsonElement jsonElement = JsonParser.parseString(json);
// 该 JSON 文本最顶层的 JSON 模型是一个 JsonArray
JsonArray jsonArray = (JsonArray) jsonElement;
// JsonArray 的第一项是一个 JsonObject
JsonObject jsonObject = (JsonObject) jsonArray.get(0);
// 该 JsonObject 中 key 为 "name" 的值
JsonPrimitive name = (JsonPrimitive) jsonObject.get("name");
// 该 JsonObject 中 key 为 "age" 的值
JsonPrimitive age = (JsonPrimitive) jsonObject.get("age");
// 往 JsonObject 中添加键值对,或者修改 value
jsonObject.addProperty("city", "beijing");
jsonObject.addProperty("age", 25);
// 往 JsonArray 中删除一项,或者添加一项
jsonArray.remove(1);
jsonArray.add("first new item");
// 各种 Json 模型对象可以直接 new 出来,null 则推荐 JsonNull.INSTANCE
jsonArray.add(new JsonPrimitive("second new item"));
// 直接 print 可以打印 JSON 文本
System.out.println(jsonElement);
}
}
三、总结
介绍了Jaskson
和Gson
的动态JSON对象的模型与基本使用方式,至于这两个 JSON 库基础的序列化与反序列化、或者动态JSON对象更进一步的使用方式 可以自己读一下二者的文档(Gson Jackson)。个人虽然平时用Jackson
比较多,但是感觉Gson
更加简洁。
TODO 有空更一篇 JsonPath 的介绍。