You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在JsonNode/ObjectNode中动态替换指定键的JSON节点值?

如何在动态结构的JsonNode中替换指定键的值(Java Jackson)

嘿,这个场景我之前做需求的时候刚好碰到过!确实,Jackson的JsonNode本身是不可变的,直接用putreplace方法根本行不通——尤其是当你不知道目标键的具体嵌套路径时,必须得遍历整个JSON结构来找目标键。

核心思路

我们需要递归遍历所有JSON节点,找到所有匹配目标键(这里是zipcode)的字段,然后替换它的值。注意要把不可变的JsonNode转换成可变的ObjectNode(Jackson的可变节点实现)才能修改内容,还要处理数组节点的情况(如果你的JSON里有数组的话)。

完整实现代码

下面是一个可直接复用的工具类方法,支持替换所有匹配目标键且旧值一致的节点:

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.ObjectNode;

public class JsonNodeModifier {
    private static final ObjectMapper objectMapper = new ObjectMapper();

    // 替换指定键的旧值为新值,支持任意嵌套结构
    public static JsonNode replaceValueByKey(JsonNode rootNode, String targetKey, String oldValue, String newValue) {
        // 先把根节点转为可变的ObjectNode(如果是对象的话)
        if (rootNode.isObject()) {
            ObjectNode objectNode = (ObjectNode) rootNode;
            // 遍历所有字段
            objectNode.fields().forEachRemaining(entry -> {
                String key = entry.getKey();
                JsonNode value = entry.getValue();

                // 如果当前键是目标键,且值匹配旧值,直接替换
                if (targetKey.equals(key) && oldValue.equals(value.asText())) {
                    objectNode.put(key, newValue);
                }
                // 否则递归处理子节点
                else if (value.isObject() || value.isArray()) {
                    replaceValueByKey(value, targetKey, oldValue, newValue);
                }
            });
        }
        // 处理数组节点,遍历每个元素递归处理
        else if (rootNode.isArray()) {
            ArrayNode arrayNode = (ArrayNode) rootNode;
            for (int i = 0; i < arrayNode.size(); i++) {
                JsonNode element = arrayNode.get(i);
                replaceValueByKey(element, targetKey, oldValue, newValue);
            }
        }
        return rootNode;
    }

    // 测试用例
    public static void main(String[] args) throws Exception {
        // 示例JSON一
        String json1 = "{\"company\": \"xyz\", \"employee\": {\"name\": \"abc\", \"address\": {\"zipcode\": \"021566\"}}}";
        // 示例JSON二
        String json2 = "{\"name\": \"abc\", \"address\": {\"zipcode\": \"021566\"}}";

        JsonNode modifiedJson1 = replaceValueByKey(objectMapper.readTree(json1), "zipcode", "021566", "566258");
        JsonNode modifiedJson2 = replaceValueByKey(objectMapper.readTree(json2), "zipcode", "021566", "566258");

        // 打印修改后的结果
        System.out.println(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(modifiedJson1));
        System.out.println(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(modifiedJson2));
    }
}

关键细节说明

  • 不可变 vs 可变节点:Jackson的JsonNode是只读的,必须转成ObjectNodeArrayNode才能修改内容,这也是直接用JsonNode.put()无效的原因。
  • 递归遍历:不管目标键嵌套多少层,递归都能找到它;如果JSON里有数组,也会遍历数组中的每个元素进行处理。
  • 旧值匹配:代码里加了旧值判断,如果你想替换所有zipcode键的值(不管原来是什么),直接去掉oldValue.equals(value.asText())这个条件就行。

测试结果

运行上面的main方法,两个示例JSON的zipcode值都会被成功替换成566258,输出的格式化JSON如下:

{
  "company" : "xyz",
  "employee" : {
    "name" : "abc",
    "address" : {
      "zipcode" : "566258"
    }
  }
}
{
  "name" : "abc",
  "address" : {
    "zipcode" : "566258"
  }
}

内容的提问来源于stack exchange,提问作者Sangeetharaj

火山引擎 最新活动