遍历JsonNode查找指定节点父节点:REST响应自定义反序列化需求
如何在Jackson的JsonNode中通过key值找到对应的value节点?
首先,先明确你的目标JSON结构(格式化后更清晰):
{ "someField": [ { "key": "foo", "value": { "left": "bar_left", "right": "bar_right" } }, { "key": "foo2", "value": { "left": "bar_left2", "right": "bar_right2" } } ], "anotherField": [ { "key": "foo3", "value": { "left": "bar_left", "right": "bar_right" } }, { "key": "foo4", "value": { "left": "bar_left2", "right": "bar_right2" } } ], "someMoreField": {} }
你需要根据唯一的key值找到对应的left和right,但JsonNode没有getParent()方法,所以得在遍历的时候手动跟踪父节点的引用。下面是几种可行的实现方式:
方法1:递归遍历(简洁易读)
递归是最直观的方式,在遍历每个节点时传递其父节点的引用,一旦找到目标key就返回对应的父节点:
public static JsonNode findParentByKey(JsonNode node, String targetKey, JsonNode parent) { // 处理对象节点 if (node.isObject()) { // 检查当前节点是否包含目标key if (node.has("key") && node.get("key").asText().equals(targetKey)) { return parent; } // 遍历所有子字段 Iterator<Map.Entry<String, JsonNode>> fields = node.fields(); while (fields.hasNext()) { Map.Entry<String, JsonNode> entry = fields.next(); JsonNode result = findParentByKey(entry.getValue(), targetKey, node); if (result != null) { return result; } } } // 处理数组节点 else if (node.isArray()) { for (JsonNode element : node) { JsonNode result = findParentByKey(element, targetKey, node); if (result != null) { return result; } } } return null; } // 使用示例 JsonNode rootNode = ...; // 你的根节点实例 JsonNode parentNode = findParentByKey(rootNode, "foo", null); if (parentNode != null) { JsonNode valueNode = parentNode.get("value"); String left = valueNode.get("left").asText(); String right = valueNode.get("right").asText(); System.out.println("Left: " + left + ", Right: " + right); }
优点:代码简洁,逻辑清晰;缺点:如果JSON层级极深(比如超过JVM栈深度),会抛出StackOverflowError。
方法2:迭代式遍历(避免栈溢出)
如果你的JSON可能有非常深的层级,用迭代+栈的方式来跟踪父节点更安全:
import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collections; import java.util.Deque; import java.util.Iterator; import java.util.Map; public static JsonNode findParentByKeyIterative(JsonNode rootNode, String targetKey) { Deque<JsonNode> nodeStack = new ArrayDeque<>(); Deque<JsonNode> parentStack = new ArrayDeque<>(); nodeStack.push(rootNode); parentStack.push(null); while (!nodeStack.isEmpty()) { JsonNode current = nodeStack.pop(); JsonNode parent = parentStack.pop(); if (current.isObject()) { // 检查是否是目标节点 if (current.has("key") && current.get("key").asText().equals(targetKey)) { return parent; } // 反向压栈保证遍历顺序和递归一致(可选) ArrayList<Map.Entry<String, JsonNode>> entries = new ArrayList<>(current.fields()); Collections.reverse(entries); for (Map.Entry<String, JsonNode> entry : entries) { nodeStack.push(entry.getValue()); parentStack.push(current); } } else if (current.isArray()) { ArrayList<JsonNode> elements = new ArrayList<>(current); Collections.reverse(elements); for (JsonNode element : elements) { nodeStack.push(element); parentStack.push(current); } } } return null; } // 使用示例 JsonNode parentNode = findParentByKeyIterative(rootNode, "foo"); if (parentNode != null) { JsonNode valueNode = parentNode.get("value"); // 处理left和right... }
优点:不会出现栈溢出问题,适合大型/深层JSON;缺点:代码比递归稍复杂。
方法3:精准遍历(最高效)
既然你知道JSON的结构是「根节点下的数组字段包含key和value对象」,可以直接遍历这些数组,跳过无关节点,效率最高:
import java.util.Iterator; import java.util.Map; import java.util.Optional; public static Optional<JsonNode> findValueByKey(JsonNode rootNode, String targetKey) { // 遍历根节点的所有字段 Iterator<Map.Entry<String, JsonNode>> rootFields = rootNode.fields(); while (rootFields.hasNext()) { Map.Entry<String, JsonNode> entry = rootFields.next(); JsonNode fieldValue = entry.getValue(); if (fieldValue.isArray()) { // 遍历数组中的每个对象 for (JsonNode item : fieldValue) { if (item.has("key") && item.get("key").asText().equals(targetKey)) { return Optional.of(item.get("value")); } } } } return Optional.empty(); } // 使用示例 Optional<JsonNode> valueNodeOpt = findValueByKey(rootNode, "foo"); valueNodeOpt.ifPresent(valueNode -> { String left = valueNode.get("left").asText(); String right = valueNode.get("right").asText(); System.out.println("Left: " + left + ", Right: " + right); });
优点:遍历范围最小,性能最好;缺点:依赖固定的JSON结构,如果结构变化需要调整代码。
内容的提问来源于stack exchange,提问作者Maciej Treder
相关产品推荐
相关产品推荐

