如何使用JsonPath动态创建路径并设置未存在的文档字段?
解决JsonPath设置不存在字段时自动创建中间节点的问题
默认情况下,JsonPath的set方法不会自动创建路径中缺失的中间节点,直接对空文档执行doc.set(JsonPath.compile("$.some.array[0].value"), "abc")会失败。要实现需求,你可以手动解析JsonPath的路径分段(令牌),遍历并创建缺失的节点结构,再执行set操作。
实现步骤
- 编译目标JsonPath,获取路径的各个分段信息;
- 从根文档开始,逐个遍历路径分段(跳过最后一个要设置的字段);
- 根据分段类型(属性节点/数组索引节点),创建对应的空结构(Map或List);
- 完成中间节点创建后,再调用
set方法设置目标值。
代码实现
工具类:自动创建缺失节点
import com.jayway.jsonpath.*; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class JsonPathNodeCreator { public static void createMissingNodes(Object document, String jsonPath) { CompiledJsonPath compiledPath = JsonPath.compile(jsonPath); Path path = compiledPath.getRootPath(); Object currentNode = document; // 遍历路径的前n-1个分段,最后一个是要赋值的字段,无需提前创建 for (int i = 0; i < path.getSegments().size() - 1; i++) { Segment segment = path.getSegments().get(i); if (segment.isArraySegment()) { handleArraySegment(currentNode, (ArraySegment) segment, path.getSegments().get(i + 1)); currentNode = getCurrentArrayNode(currentNode, segment); } else { handleObjectSegment(currentNode, segment, path.getSegments().get(i + 1)); currentNode = ((Map<String, Object>) currentNode).get(segment.getPathFragment()); } } } private static void handleArraySegment(Object parentNode, ArraySegment arraySegment, Segment nextSegment) { Map<String, Object> parentMap = (Map<String, Object>) parentNode; String arrayKey = arraySegment.getPathFragment(); int index = arraySegment.getIndex(); // 如果父节点中没有该数组,创建空列表 if (!parentMap.containsKey(arrayKey)) { parentMap.put(arrayKey, new ArrayList<>()); } List<Object> array = (List<Object>) parentMap.get(arrayKey); // 确保列表长度足够容纳目标索引,不足则填充空对象(根据下一个节点类型决定是Map还是List) while (array.size() <= index) { Object emptyNode = nextSegment.isArraySegment() ? new ArrayList<>() : new HashMap<>(); array.add(emptyNode); } } private static void handleObjectSegment(Object parentNode, Segment segment, Segment nextSegment) { Map<String, Object> parentMap = (Map<String, Object>) parentNode; String key = segment.getPathFragment(); // 如果父节点中没有该属性,创建对应的空结构(下一个是数组则创建List,否则创建Map) if (!parentMap.containsKey(key)) { Object emptyNode = nextSegment.isArraySegment() ? new ArrayList<>() : new HashMap<>(); parentMap.put(key, emptyNode); } } private static Object getCurrentArrayNode(Object parentNode, Segment segment) { Map<String, Object> parentMap = (Map<String, Object>) parentNode; List<Object> array = (List<Object>) parentMap.get(segment.getPathFragment()); ArraySegment arraySegment = (ArraySegment) segment; return array.get(arraySegment.getIndex()); } }
使用示例
import com.jayway.jsonpath.JsonPath; import java.util.HashMap; import java.util.Map; public class Demo { public static void main(String[] args) { // 空文档 Map<String, Object> doc = new HashMap<>(); String targetPath = "$.some.array[0].value"; String targetValue = "abc"; // 先创建缺失的中间节点 JsonPathNodeCreator.createMissingNodes(doc, targetPath); // 再设置目标值 JsonPath.parse(doc).set(targetPath, targetValue); // 输出结果 System.out.println(JsonPath.parse(doc).jsonString()); } }
说明
- 该工具类会根据路径分段的类型(属性/数组),自动创建对应的中间结构;
- 针对数组索引,会自动填充空对象直到满足目标索引的长度要求;
- 注意适配你使用的JsonPath版本,部分版本的API可能略有差异(比如
getRootPath()在旧版本中可能为getPath())。
内容的提问来源于stack exchange,提问作者Mauricio Burgos Herrera
相关产品推荐
相关产品推荐

