TreeNode浅析
Jackson 在反序列化json字符串的时候会将其转换成一棵由JsonNode为节点组成的多节点树。 每个冒号左边的key和右边的value组成JsonNode,JsonNode是抽象类。 每一种value类型(如对象{},数组[],数字)都有其对应的实现类。
下面简单分类下各种类型
类型的枚举
public enum JsonNodeType
{
ARRAY,
BINARY,
BOOLEAN,
MISSING,
NULL,
NUMBER,
OBJECT,
POJO,
STRING
}
通过JsonNode.getNodeType()可以获取当前node的类型
类型分类
上面的枚举可以简单的分为三种,分别使用下面三个方法判断
- isValueNode()
- isContainerNode()
- isMissingNode()
叶子节点
看下isValueNode()实现,除了 ARRAY、OBJECT、MISSING都是值类型。
就相当于树的叶子节点。
class JsonNode {
public final boolean isValueNode() {
switch (getNodeType()) {
case ARRAY: case OBJECT: case MISSING:
return false;
default:
return true;
}
}
}
非叶子节点
isContainerNode() 容器节点,节点下面还包含其他的分叉。 主要包含两种类型,OBJECT、ARRAY
class JsonNode {
public final boolean isContainerNode() {
final JsonNodeType type = getNodeType();
return type == JsonNodeType.OBJECT || type == JsonNodeType.ARRAY;
}
}
遍历这两种节点
- ObjectNode
使用
ObjectNode.fields()
方法获取这个节点下面属性的列表,这个方法返回的是一个迭代器直接循环处理即可。
Iterator<Map.Entry<String, JsonNode>> iterator = node.fields();
while (iterator.hasNext()) {
Map.Entry<String, JsonNode> entry = iterator.next();
}
- ArrayNode
ArrayNode.size()
方法获取数组长度循环处理。
for (int i = 0; i < node.size(); i++) {
JsonNode arrChild = node.get(i);
}
封装JacksonUtil
public class JacksonUtil {
private JacksonUtil() {
throw new UnsupportedOperationException();
}
private static final ObjectMapper MAPPER = new ObjectMapper();
private static final DefaultPrettyPrinter PRETTY_PRINTER = new DefaultPrettyPrinter();
static {
//json中可以有注释
MAPPER.enable(JsonParser.Feature.ALLOW_COMMENTS);
//重复检测
MAPPER.enable(JsonParser.Feature.STRICT_DUPLICATE_DETECTION);
//宽松的json序列化,java类中字段可以和json不完全匹配
MAPPER.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
//格式化相关
DefaultIndenter indenter = new DefaultIndenter(" ", DefaultIndenter.SYS_LF);
PRETTY_PRINTER.indentArraysWith(indenter);
PRETTY_PRINTER.indentArraysWith(indenter);
}
/**
* 对象 转换成json string
*/
public static String toJson(Object obj) {
try {
return MAPPER.writeValueAsString(obj);
} catch (JsonProcessingException e) {
throw new UncheckedIOException(e);
}
}
/**
* 格式化之后的json string
*/
public static String toPrettyJson(Object obj) {
try {
return MAPPER.writer(PRETTY_PRINTER).writeValueAsString(obj);
} catch (JsonProcessingException e) {
throw new UncheckedIOException(e);
}
}
/**
* 反序列化json
* @return 入参的类型泛型实例化对象
*/
public static <T> T fromJson(String json, Class<T> valueType) {
try {
return MAPPER.readValue(json, valueType);
} catch (JsonProcessingException e) {
throw new UncheckedIOException(e);
}
}
/**
* 反序列化json
* @return JavaType对象的类型实例
*/
public static <T> T fromJson(String json, JavaType javaType) {
try {
return MAPPER.readValue(json, javaType);
} catch (JsonProcessingException e) {
throw new UncheckedIOException(e);
}
}
/**
* 反序列化json,转换成集合,集合中的元素为泛型对象
* @return JavaType对象的类型实例
*/
public static <E, T extends Collection<E>> T ofJsonCollection(String json,
Class<? extends Collection> CollectionType, Class<E> itemType) {
try {
return MAPPER.readValue(json, MAPPER.getTypeFactory().constructCollectionType(CollectionType, itemType));
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
/**
* 反序列化json,转换成Map
* @return JavaType对象的类型实例
*/
public static <K, V, T extends Map<K, V>> T ofJsonMap(String json,
Class<? extends Map> mapType, Class<K> keyType, Class<V> valueType) {
try {
return MAPPER.readValue(json, MAPPER.getTypeFactory().constructMapType(mapType, keyType, valueType));
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
}
使用 MAPPER.getTypeFactory().constructType()
、MAPPER.getTypeFactory().constructMapType
等方法可以扩展出多种类型的嵌套
使用Jackson处理json嵌套
json 字符串中存在多层嵌套json的情况,使用jackson将嵌套的json解开。 并且支持按照原来的嵌套层级进行反编码
package com.peng.jackson;
import static com.fasterxml.jackson.databind.node.JsonNodeType.STRING;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang3.tuple.Pair;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
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.JsonNodeType;
import com.fasterxml.jackson.databind.node.ObjectNode;
/**
* JacksonConverter
*
* @author lupeng
* Created on 2022-04-16
*/
public class JacksonConverter {
public static void main(String[] args) throws JsonProcessingException {
String json = """
{
"arr": [
{
"name": "jack",
"age": 11,
"factor": 0.66
},
{
"name": "guoguo",
"age": 2,
"factor": 0.99
}
],
"size": 1234567890,
"data": "{\"extra\":{\"firstName\":\"zhang\",\"lastName\":\"san\"}, \"arr1\":[1,2,3]}"
}
""".strip();
JacksonConverter converter = new JacksonConverter();
JsonNode decode = converter.decode(json);
String jsonstr = MAPPER.writeValueAsString(decode);
System.out.println(jsonstr);
System.out.println("--------------------------");
JsonNode encode = converter.encode(jsonstr);
String string = MAPPER.writeValueAsString(encode);
System.out.println(string);
}
private static final ObjectMapper MAPPER = new ObjectMapper();
static {
//json中可以有注释
MAPPER.enable(JsonParser.Feature.ALLOW_COMMENTS);
//重复检测
MAPPER.enable(JsonParser.Feature.STRICT_DUPLICATE_DETECTION);
//宽松的json序列化,java类中字段可以和json不完全匹配
MAPPER.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
}
private Set<String> convertedJsonNodes = new HashSet<>();
public JsonNode decode(String json) {
try {
JsonNode root = MAPPER.readTree(json);
String path = "$";
recursiveParser(root, path, false);
return root;
} catch (JsonProcessingException e) {
return null;
}
}
public JsonNode encode(String json) {
try {
JsonNode root = MAPPER.readTree(json);
String path = "$";
recursiveParser(root, path, true);
return root;
} catch (JsonProcessingException e) {
return null;
}
}
private void recursiveParser(JsonNode node, String path, boolean isEncode) {
// 获取jackson的Node节点类型
JsonNodeType nodeType = node.getNodeType();
switch (nodeType) {
case OBJECT -> {
ObjectNode objNode = (ObjectNode) node;
Iterator<Map.Entry<String, JsonNode>> iterator = objNode.fields();
while (iterator.hasNext()) {
Map.Entry<String, JsonNode> entry = iterator.next();
String key = entry.getKey();
JsonNode value = entry.getValue();
String currPath = path + "." + key;
if (isEncode && convertedJsonNodes.contains(currPath)) {
recursiveParser(value, currPath, true);
((ObjectNode) node).put(key, value.toString());
continue;
}
Pair<Boolean, JsonNode> result = tryDecodeJsonNode(value);
if (result.getLeft()) {
convertedJsonNodes.add(currPath);
JsonNode decodeJsonNode = result.getRight();
objNode.put(key, decodeJsonNode);
value = decodeJsonNode;
}
recursiveParser(value, currPath, isEncode);
}
}
case ARRAY -> {
ArrayNode arrayNode = (ArrayNode) node;
for (int i = 0; i < arrayNode.size(); i++) {
JsonNode value = arrayNode.get(i);
String currPath = path + "[" + i + "]";
if (isEncode && convertedJsonNodes.contains(currPath)) {
recursiveParser(value, currPath, true);
arrayNode.insert(i, value.toString());
continue;
}
Pair<Boolean, JsonNode> result = tryDecodeJsonNode(value);
if (result.getLeft()) {
convertedJsonNodes.add(currPath);
JsonNode decodeJsonNode = result.getRight();
((ArrayNode) node).insert(i, decodeJsonNode);
value = decodeJsonNode;
}
recursiveParser(value, currPath, isEncode);
}
}
}
}
private Pair<Boolean, JsonNode> tryDecodeJsonNode(JsonNode jsonNode) {
if (jsonNode.getNodeType() != STRING) {
return Pair.of(false, null);
}
try {
JsonNode node = MAPPER.readTree(jsonNode.asText());
return Pair.of(true, node);
} catch (JsonProcessingException e) {
return Pair.of(false, null);
}
}
}