You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用net.minidev.json比较复杂JSON对象时如何忽略指定深层字段?

如何忽略复杂JSON对象中的特定深层字段进行单元测试比较?

你使用net.minidev.json库编写单元测试时,需要比较两个复杂JSONObject但忽略某个始终可变的深层字段(如timestamp),直接用Assertions.assertEquals会因为该字段值不同导致测试失败。下面提供两种简单可行的方案,无需编写复杂的自定义比较器:

方案一:递归删除目标深层字段

通过编写工具方法,递归遍历JSON结构,找到指定路径的字段并删除,之后再进行比较。这种方式能确保两个JSON对象在忽略目标字段后结构和值完全一致。

工具类代码

import net.minidev.json.JSONArray;
import net.minidev.json.JSONObject;

public class JsonTestUtils {
    // 递归删除指定路径的深层字段
    public static void removeDeepField(Object json, String[] fieldPath) {
        if (fieldPath == null || fieldPath.length == 0) {
            return;
        }

        Object currentNode = json;
        // 遍历到目标字段的父节点
        for (int i = 0; i < fieldPath.length - 1; i++) {
            String key = fieldPath[i];
            if (currentNode instanceof JSONObject) {
                currentNode = ((JSONObject) currentNode).get(key);
            } else if (currentNode instanceof JSONArray) {
                // 支持路径中包含数组索引(需传入数字字符串,如"0")
                try {
                    int index = Integer.parseInt(key);
                    currentNode = ((JSONArray) currentNode).get(index);
                } catch (NumberFormatException e) {
                    // 路径格式错误,直接终止
                    return;
                }
            } else {
                // 中间路径不存在,终止操作
                return;
            }

            if (currentNode == null) {
                return;
            }
        }

        // 删除最后一级的目标字段
        String finalKey = fieldPath[fieldPath.length - 1];
        if (currentNode instanceof JSONObject) {
            ((JSONObject) currentNode).remove(finalKey);
        } else if (currentNode instanceof JSONArray) {
            try {
                int index = Integer.parseInt(finalKey);
                ((JSONArray) currentNode).remove(index);
            } catch (NumberFormatException e) {
                return;
            }
        }
    }
}

测试代码改造

JSONParser parser = new JSONParser(JSONParser.MODE_JSON_SIMPLE);
JSONObject jsonObject1 = (JSONObject) parser.parse(expectedErrorMessage);
JSONObject jsonObject2 = (JSONObject) parser.parse(lastMessage.toString());

// 指定要忽略的深层字段路径,例如["data","metadata","timestamp"]
String[] ignoredFieldPath = {"path", "to", "field"};
JsonTestUtils.removeDeepField(jsonObject1, ignoredFieldPath);
JsonTestUtils.removeDeepField(jsonObject2, ignoredFieldPath);

// 此时比较的是忽略目标字段后的JSON对象
Assertions.assertEquals(jsonObject1, jsonObject2);

方案二:统一设置目标字段为固定值

如果不想删除字段,也可以将两个JSON对象的目标字段设置为同一个固定值,确保比较时该字段不会影响结果,逻辑和方案一类似,只是将删除操作改为赋值操作。

工具类扩展方法

// 递归设置指定路径的深层字段为固定值
public static void setDeepField(Object json, String[] fieldPath, Object fixedValue) {
    if (fieldPath == null || fieldPath.length == 0) {
        return;
    }

    Object currentNode = json;
    // 遍历到目标字段的父节点
    for (int i = 0; i < fieldPath.length - 1; i++) {
        String key = fieldPath[i];
        if (currentNode instanceof JSONObject) {
            currentNode = ((JSONObject) currentNode).get(key);
        } else if (currentNode instanceof JSONArray) {
            try {
                int index = Integer.parseInt(key);
                currentNode = ((JSONArray) currentNode).get(index);
            } catch (NumberFormatException e) {
                return;
            }
        } else {
            return;
        }

        if (currentNode == null) {
            return;
        }
    }

    // 设置最后一级的目标字段值
    String finalKey = fieldPath[fieldPath.length - 1];
    if (currentNode instanceof JSONObject) {
        ((JSONObject) currentNode).put(finalKey, fixedValue);
    } else if (currentNode instanceof JSONArray) {
        try {
            int index = Integer.parseInt(finalKey);
            ((JSONArray) currentNode).set(index, fixedValue);
        } catch (NumberFormatException e) {
            return;
        }
    }
}

测试代码改造

JSONParser parser = new JSONParser(JSONParser.MODE_JSON_SIMPLE);
JSONObject jsonObject1 = (JSONObject) parser.parse(expectedErrorMessage);
JSONObject jsonObject2 = (JSONObject) parser.parse(lastMessage.toString());

String[] targetFieldPath = {"path", "to", "field"};
// 将两个对象的目标字段都设为同一个固定值
JsonTestUtils.setDeepField(jsonObject1, targetFieldPath, "ignored_timestamp");
JsonTestUtils.setDeepField(jsonObject2, targetFieldPath, "ignored_timestamp");

Assertions.assertEquals(jsonObject1, jsonObject2);

方案对比

  • 方案一更彻底,直接移除无关字段,避免后续其他字段修改带来的干扰;
  • 方案二保留字段结构,适合需要维持JSON完整性的场景;
  • 两种方案都比自定义比较器更简洁,无需重写复杂的递归比较逻辑,复用性强。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 06:03:24