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

Java中忽略指定属性比较JSON数组内JSON对象的实现方案

问题场景

现有如下交易结构JSON示例,数组内包含多个交易对象:

{
    "payload": {
        "header": [
            {
                "messageId": "10a0df00-c55c-4147-a3bf-e10dc9882768",
                "transactionId": "10000001",
                "customerId": "customer4148",
                "customerGroupId": "USA",
                "transactionStatus": "completed",
                "creationTimestamp": "2022-06-15 06:36:23.798",
                "currency": "USD",
                "offset": 30
            },
            {
                "messageId": "9cg8f839-ab1e-467f-b679-a3aa4f390f2a",
                "transactionId": "10000001",
                "customerId": "customer4148",
                "customerGroupId": "USA",
                "transactionStatus": "completed",
                "creationTimestamp": "2022-06-15 06:36:23.798",
                "currency": "USD",
                "offset": 30
            }
        ]
    }
}

此前使用JsonAssert实现自定义比较逻辑,通过自定义比较器忽略messageId字段,实现代码如下:

JSONAssert.assertEquals(expectedResponseBody, responseBody,
            new CustomComparator(JSONCompareMode.LENIENT,
                new Customization("messageId", (o1, o2) -> true)));

目前因JsonAssert依赖存在已知安全漏洞,被CI流水线禁止引入,需要寻找可高效比较JSON数组内多个JSONObject、且比较过程中自动忽略messageId字段的替代实现。

推荐实现方案

优先选择项目已有通用依赖实现,避免引入新的第三方包带来额外安全风险:

方案1:基于Jackson实现(推荐,绝大多数Java项目已内置依赖)

Jackson是Spring生态默认集成的JSON处理包,无公开高危漏洞,实现逻辑为:递归移除两个待比较JSON中所有层级的messageId字段(包含数组内嵌套对象的对应字段),再直接做节点等值比较,支持宽松/严格模式切换。
实现代码示例:

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class JsonCompareUtil {
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
    // 配置需要忽略比较的字段列表
    private static final Set<String> IGNORE_FIELDS = Set.of("messageId");

    public static void assertJsonEquals(String expected, String actual) throws Exception {
        JsonNode expectedNode = OBJECT_MAPPER.readTree(expected);
        JsonNode actualNode = OBJECT_MAPPER.readTree(actual);
        // 递归移除所有待忽略字段
        removeIgnoreFields(expectedNode);
        removeIgnoreFields(actualNode);
        // 执行节点等值比较
        if (!expectedNode.equals(actualNode)) {
            throw new AssertionError(String.format("JSON比较不通过,预期:%s,实际:%s", expectedNode, actualNode));
        }
    }

    private static void removeIgnoreFields(JsonNode node) {
        if (node.isObject()) {
            ObjectNode objectNode = (ObjectNode) node;
            // 移除当前对象层级的忽略字段
            IGNORE_FIELDS.forEach(objectNode::remove);
            // 递归处理所有子字段
            Iterator<Map.Entry<String, JsonNode>> fields = objectNode.fields();
            while (fields.hasNext()) {
                removeIgnoreFields(fields.next().getValue());
            }
        } else if (node.isArray()) {
            // 遍历处理数组内所有元素
            for (JsonNode arrayItem : node) {
                removeIgnoreFields(arrayItem);
            }
        }
    }
}

注意:如果业务场景下JSON数组是无序的,可在移除忽略字段后,对数组节点按业务唯一键(比如transactionId)排序后再做等值判断,避免元素顺序不一致导致的误判。

方案2:基于AssertJ递归比较(适合已集成AssertJ做单元测试的项目)

如果项目单元测试已经使用AssertJ,不需要额外引入JSON处理依赖,可先将JSON反序列化为Map结构,再通过AssertJ的递归比较API忽略指定字段:

import static org.assertj.core.api.Assertions.assertThat;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import java.util.Map;

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

    @Test
    void testJsonCompare() throws Exception {
        Map<String, Object> expected = objectMapper.readValue(expectedResponseBody, new TypeReference<>() {});
        Map<String, Object> actual = objectMapper.readValue(responseBody, new TypeReference<>() {});
        
        assertThat(actual)
                .usingRecursiveComparison()
                .ignoringFieldsMatchingRegexes(".*messageId") // 忽略所有层级的messageId字段
                .ignoringCollectionOrder() // 按需开启:忽略集合元素顺序
                .isEqualTo(expected);
    }
}

该方案支持多种宽松模式配置,比如忽略空值、忽略字段大小写等,可根据测试需求灵活调整。

方案优势

  • 不需要引入JsonAssert依赖,所有依赖包均为Java项目常规内置依赖,安全漏洞风险极低
  • 支持任意层级嵌套的JSON结构,自动处理数组内对象的字段忽略逻辑
  • 性能优于JsonAssert,大JSON体比较场景下无明显性能损耗

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 10:33:11