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

Java Jackson如何实现忽略键与数组元素顺序的JSON对比

基于Jackson实现满足需求的JSON对比功能

核心思路

通过Jackson将两个JSON字符串解析为JsonNode树结构,递归遍历节点做对比,针对不同节点类型做特殊处理:

  • 忽略对象节点的键排序差异,同时严格校验键集合完全一致,任意一方存在多余字段直接判定不相等
  • 忽略数组节点的元素排序差异,同时保证元素的种类和数量完全匹配
  • 基础值类型直接做等值对比

前置依赖

确保项目已经引入Jackson核心模块,常规SpringBoot项目默认已集成,手动引入的Maven配置如下:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>根据你的项目版本选择即可</version>
</dependency>

完整实现代码

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ArrayNode;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.ValueNode;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class JsonCompareUtils {
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    public static boolean compareJson(String json1, String json2) throws JsonProcessingException {
        JsonNode node1 = OBJECT_MAPPER.readTree(json1);
        JsonNode node2 = OBJECT_MAPPER.readTree(json2);
        return compareJsonNode(node1, node2);
    }

    private static boolean compareJsonNode(JsonNode node1, JsonNode node2) {
        // 节点类型不同直接不相等
        if (node1.getNodeType() != node2.getNodeType()) {
            return false;
        }

        // 处理值类型节点(字符串、数字、布尔、null等)
        if (node1 instanceof ValueNode) {
            return node1.equals(node2);
        }

        // 处理对象类型节点
        if (node1 instanceof ObjectNode obj1 && node2 instanceof ObjectNode obj2) {
            // 先判断字段数量是否一致,不一致说明有多余字段
            if (obj1.size() != obj2.size()) {
                return false;
            }
            // 遍历所有字段逐一对比
            Iterator<String> fieldNames = obj1.fieldNames();
            while (fieldNames.hasNext()) {
                String fieldName = fieldNames.next();
                if (!obj2.has(fieldName)) {
                    return false;
                }
                if (!compareJsonNode(obj1.get(fieldName), obj2.get(fieldName))) {
                    return false;
                }
            }
            return true;
        }

        // 处理数组类型节点
        if (node1 instanceof ArrayNode arr1 && node2 instanceof ArrayNode arr2) {
            // 数组长度不同直接不相等
            if (arr1.size() != arr2.size()) {
                return false;
            }
            // 把第二个数组的元素转成列表,方便匹配后移除避免重复匹配
            List<JsonNode> arr2Elements = new ArrayList<>();
            arr2.forEach(arr2Elements::add);
            // 遍历第一个数组的每个元素,在第二个数组中找匹配项
            for (JsonNode elem1 : arr1) {
                boolean matched = false;
                Iterator<JsonNode> it = arr2Elements.iterator();
                while (it.hasNext()) {
                    JsonNode elem2 = it.next();
                    if (compareJsonNode(elem1, elem2)) {
                        it.remove();
                        matched = true;
                        break;
                    }
                }
                if (!matched) {
                    return false;
                }
            }
            // 所有元素都匹配完成
            return arr2Elements.isEmpty();
        }
        // 其他未知类型节点默认不相等
        return false;
    }
}

效果验证

可以通过以下场景测试是否符合需求:

  • 测试场景1:对象键顺序不同、数组元素顺序不同,内容完全一致:返回true
  • 测试场景2:其中一个JSON多了任意字段:返回false
  • 测试场景3:数组元素数量不一致:返回false
  • 测试场景4:数组元素数量一致但内容存在差异:返回false

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 00:24:02