使用 Java 修改指定节点中的 json 字段值

Modify json field value in specified node using Java

例如我有Json这样的

{
name: Alex,
lastName: Smith,
delivery: {
   street: 7599 King George Blvd,
   name : PIETER CIERE
},
paymentAddressData: [
    {
    email: mail@email.com,
    name: Bobby,
    phone2: 123456
     },
    {
    email: mail@email.com,
    name: Bobby,
    phone2: 123456
     }
]

}

而且我需要更改“名称”字段中的值,仅在所有条目的根节点和“paymentAddressData”arrayNode 中。在所有其他地方,价值必须保持原样。 我如何使用 Jackson 或其他工具来实现它?如有任何建议,我们将不胜感激!

我为我们的测试自动化(通过 REST Assured)实现了我自己的动态方法,您可以在其中使用 KeyPath 约定(见下文)填充 HashMap,以便 一次修改任意多个键 和最后 return JSONObject 和 JSONArray 的相应新 Json-String(仅以一个“[”和“]”开始和结束)。我从来不需要使用修改 JSON 以多个方括号开头的数组,这些方括号不应该经常使用。

只需将您的来源 JSON 提取为修改它的字符串,然后根据 file/path.

回写

这是一个 JSON 示例:

{
    "personalDetails": [
        {
            "name": "John",
            "city": "Berlin",
            "job": "Teacher",
            "age": 42,
            "children": [
                {
                    "name": "Kevin",
                    "city": "Berlin",
                    "age": 14
                },
                {
                    "name": "Lisa",
                    "city": "Berlin",
                    "age": 8
                }
            ]
        },
        {
            "name": "Mark",
            "city": "Oslo",
            "job": "Doctor",
            "children": []
        }
    ]
}

例如,您要修改以下键:

  • 年龄(丽莎) -> 来自89KeyPath"personalDetails[0].children[1].age"

  • 工作(标记) -> 来自"Doctor""Chiropractor"KeyPath"personalDetails[1].job"

根据我的示例,使用您给定的 Json-String 并遵循 HashMap 来填充下面我的动态方法中的参数:

HashMap<String, Object> modifyMap = new HashMap<String, Object>() {{
            put("personalDetails[0].children[1].age", 9);
            put("personalDetails[1].job", "Chiropractor");
        }};

使用提取的、修改的 Json-String

调用此方法
// Modify any given JsonObject or JsonArray due to KeyPath conventions
protected static String modifiedJson(String oldJson, Map<String, Object> modifyMap) {

    JSONObject defaultJson = new JSONObject("{}");
    Object newJson = defaultJson;

    Pattern pattern = Pattern.compile("\[(\d+)]");

    for (String keyPath : modifyMap.keySet()) {

        String[] keyPathTrimmings = keyPath.split("\.");
        int sizeOfTrimmings = keyPathTrimmings.length;

        JSONObject[] jsonObjects = new JSONObject[sizeOfTrimmings];
        Matcher matcher = pattern.matcher(keyPathTrimmings[sizeOfTrimmings - 1]);
        newJson = matcher.find(0) ?
                newJson.equals(defaultJson) ? new JSONArray(oldJson) : newJson :
                newJson.equals(defaultJson) ? new JSONObject(oldJson) : newJson;
        jsonObjects[0] = matcher.find(0) ?
                newJson instanceof JSONArray ? ((JSONArray) newJson).getJSONObject(Integer.parseInt(matcher.group(1))) : defaultJson :
                newJson instanceof JSONObject ? (JSONObject) newJson : defaultJson;

        for (int pos = 0; pos < sizeOfTrimmings; pos++) {

            String actualKey = keyPathTrimmings[pos].replaceAll("\[(\d+)]", "");

            if (pos == sizeOfTrimmings - 1) {
                jsonObjects[pos].put(actualKey, modifyMap.get(keyPath));
            } else {
                matcher = pattern.matcher(keyPathTrimmings[pos]);
                jsonObjects[pos + 1] = matcher.find(0) ?
                        jsonObjects[pos].getJSONArray(actualKey).getJSONObject(Integer.parseInt(matcher.group(1))) :
                        jsonObjects[pos].getJSONObject(actualKey);
            }
        }
    }
    return newJson.toString();
}

与其使用 Jackson,我更喜欢 JsonPath 库, 因为它提供了更强大的 API 来访问和修改 JSON 内容以 path-based 方式。 对于一些示例,我建议阅读文章 Baeldung - Introduction to JsonPath.

使用方法JsonPath.parse and WriteContext.set 你可以用几行来完成。 以下代码将根节点中的名称替换为 "Alice" "Charlie".

所有 paymentAddressData 个节点中的名称
File file = new File("example.json");
String json = JsonPath.parse(file)
        .set("$.name", "Alice")
        .set("$.paymentAddressData[*].name", "Charlie")
        .jsonString();
System.out.println(json);

如果您想要另一个值来替换 JSON 名称, 那么您将需要调整上面代码中的 .set(...) 调用 根据您的需要。 对于更复杂的逻辑,您可能需要使用 .map(...) 而不是 .set(...).