JSON报文差异化对比

  • 方式一,使用jsonassert
  • 方式二,使用json-patch



有这么一组json字符串


java json对比差异字段 json比较返回差异java_ci


java json对比差异字段 json比较返回差异java_java json对比差异字段_02

需求是要对比json,相同可以不展示,不同需指明差异字段
前提引入jackson包

<dependencies>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>2.13.3</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-annotations</artifactId>
        <version>2.13.3</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.13.3</version>
    </dependency>
</dependencies>

方式一,使用jsonassert

使用此方法的好处是可以自定义一些对比规则(强烈推荐)

  1. 首先引入pom依赖
<dependency>
    <groupId>org.skyscreamer</groupId>
    <artifactId>jsonassert</artifactId>
    <version>1.5.1</version>
</dependency>
  1. 编写代码
public class Main {
    //与jsonStr2中orgSeqNo不一样,还有addresses中的addrType为103时的字段类型不一样
    static String jsonStr1 = "{\"orgSeqNo\":\"123123\",\"code\":200,\"person\":{\"partyId\":\"10000000001\",\"partyName\":\"张三\",\"partyCertType\":\"10100\",\"partyCertNo\":\"320925199612122314\",\"partyStatus\":\"1\",\"addresses\":[{\"addrId\":\"1\",\"partyId\":\"10000000001\",\"city\":\"苏州\",\"detailAddr\":\"相城区双塔街道33号\",\"addrType\":103,\"phone\":\"13213137625\"},{\"addrId\":\"2\",\"partyId\":\"10000000001\",\"city\":\"苏州\",\"detailAddr\":\"相城区双塔街道33号\",\"addrType\":\"101\",\"phone\":\"13213137625\"},{\"addrId\":\"3\",\"partyId\":\"10000000001\",\"city\":\"苏州\",\"detailAddr\":\"相城区双塔街道33号\",\"addrType\":\"102\",\"phone\":\"13213137625\"}]},\"message\":\"ok\"}";
    static String jsonStr2 = "{\"orgSeqNo\":\"12e9fc45c09b4a69b7aa2bbcb1313cba\",\"code\":200,\"person\":{\"partyId\":\"10000000001\",\"partyName\":\"张三\",\"partyCertType\":\"10100\",\"partyCertNo\":\"320925199612122314\",\"partyStatus\":\"1\",\"addresses\":[{\"addrId\":\"1\",\"partyId\":\"10000000001\",\"city\":\"苏州\",\"detailAddr\":\"相城区双塔街道33号\",\"addrType\":\"103\",\"phone\":\"13213137625\"},{\"addrId\":\"2\",\"partyId\":\"10000000001\",\"city\":\"苏州\",\"detailAddr\":\"相城区双塔街道33号\",\"addrType\":\"101\",\"phone\":\"13213137625\"},{\"addrId\":\"3\",\"partyId\":\"10000000001\",\"city\":\"苏州\",\"detailAddr\":\"相城区双塔街道33号\",\"addrType\":\"102\",\"phone\":\"13213137625\"}]},\"message\":\"ok\"}";
    //与jsonStr2对比,addresses数组中的顺序换了
    static String jsonStr3 = "{\"orgSeqNo\":\"12e9fc45c09b4a69b7aa2bbcb1313cba\",\"code\":200,\"person\":{\"partyId\":\"10000000001\",\"partyName\":\"张三\",\"partyCertType\":\"10100\",\"partyCertNo\":\"320925199612122314\",\"partyStatus\":\"1\",\"addresses\":[{\"addrId\":\"2\",\"partyId\":\"10000000001\",\"city\":\"苏州\",\"detailAddr\":\"相城区双塔街道33号\",\"addrType\":\"101\",\"phone\":\"13213137625\"},{\"addrId\":\"1\",\"partyId\":\"10000000001\",\"city\":\"苏州\",\"detailAddr\":\"相城区双塔街道33号\",\"addrType\":\"103\",\"phone\":\"13213137625\"},{\"addrId\":\"3\",\"partyId\":\"10000000001\",\"city\":\"苏州\",\"detailAddr\":\"相城区双塔街道33号\",\"addrType\":\"102\",\"phone\":\"13213137625\"}]},\"message\":\"ok\"}";
    //与jsonStr2对比,addresses数组中的103位数字类型
    static String jsonStr4 = "{\"orgSeqNo\":\"12e9fc45c09b4a69b7aa2bbcb1313cba\",\"code\":200,\"person\":{\"partyId\":\"10000000001\",\"partyName\":\"张三\",\"partyCertType\":\"10100\",\"partyCertNo\":\"320925199612122314\",\"partyStatus\":\"1\",\"addresses\":[{\"addrId\":\"1\",\"partyId\":\"10000000001\",\"city\":\"苏州\",\"detailAddr\":\"相城区双塔街道33号\",\"addrType\":103,\"phone\":\"13213137625\"},{\"addrId\":\"2\",\"partyId\":\"10000000001\",\"city\":\"苏州\",\"detailAddr\":\"相城区双塔街道33号\",\"addrType\":\"101\",\"phone\":\"13213137625\"},{\"addrId\":\"3\",\"partyId\":\"10000000001\",\"city\":\"苏州\",\"detailAddr\":\"相城区双塔街道33号\",\"addrType\":\"102\",\"phone\":\"13213137625\"}]},\"message\":\"ok\"}";



    public static void main(String[] args) {
        //aasdasdbc为过滤的节点,随意指定
        Customization[] customizations = {new Customization("aasdasdbc",(o1, o2) -> { return true;})};
        JSONCompareResult result = null;
        JSONCompareResult result1 = null;
        JSONCompareResult result2 = null;
        try {
            // JSONCompareMode.NON_EXTENSIBLE  不可扩展模式,可忽略数组排序
            // 宽大模式(LENIENT) 可扩展,数组不用排序
            // 严格模式(STRICT)  不可扩展, 数组严格排序
            // 严格排序模式(STRICT_ORDER)  如字面意思,可扩展
			// 扩展的意思是已有的[1,23,45]和[1,23,45,6]在STRICT_ORDER是可以的

            // 使用自定义比较规则
            result = JSONCompare.compareJSON(jsonStr1, jsonStr2, new MyCustomComparator(JSONCompareMode.NON_EXTENSIBLE, customizations));
            // 过滤orgSeqNo根节点字段
            result1  = JSONCompare.compareJSON(jsonStr1, jsonStr3, new CustomComparator(JSONCompareMode.NON_EXTENSIBLE,
                    Customization.customization("orgSeqNo", (o1, o2) -> {
                        return true;
                    })));
            // 过滤orgSeqNo根节点,以及过滤person根节点下的addresses数组节点的addrType节点字段
            result2 = JSONCompare.compareJSON(jsonStr1, jsonStr3, new CustomComparator(JSONCompareMode.NON_EXTENSIBLE,
                    Customization.customization("orgSeqNo", (o1, o2) -> { return true;}),
                    Customization.customization("person.addresses[*].addrType", (o1, o2) -> { return true;})));
            if (result.passed()) {
                System.out.println("两者相等");
            } else {
                System.out.println(result.getMessage());
            }
            
            if (result1.passed()) {
                System.out.println("两者相等");
            } else {
                System.out.println(result1.getMessage());
            }
            if (result2.passed()) {
                System.out.println("两者相等");
            } else {
                System.out.println(result2.getMessage());
            }
        } catch (JSONException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
}
  1. 对比效果
两者相等
person.addresses[addrId=1].addrType
Expected: 103
     got: 103

两者相等
  1. 上述自定义的过滤规则
public class MyCustomComparator extends CustomComparator {
    private final Collection<Customization> customizations;

    public MyCustomComparator(JSONCompareMode mode, Customization[] customizations) {
        super(mode);
        this.customizations = Arrays.asList(customizations);
    }

    //比较器默认调用此方法,如果要实现复杂逻辑,可以重写
    @Override
    public void compareValues(String prefix, Object expectedValue, Object actualValue, JSONCompareResult result) throws JSONException {
        Customization customization = getCustomization(prefix);
        if (customization != null) {
            try {
                if (!customization.matches(prefix, actualValue, expectedValue, result)) {
                    result.fail(prefix, expectedValue, actualValue);
                }
            } catch (ValueMatcherException e) {
                result.fail(prefix, e);
            }
        } else {
			// 过滤某些节点字段
            if (prefix.indexOf("orgSeqNo") != -1 || prefix.indexOf("addrType") != -1) {
                return;
            }
            // todo 可以设置一些复杂的比较,例如某个字段的数值字符串和数值可忽略,小数和某些整数可忽略

            if ((expectedValue == null && actualValue != null) || (expectedValue != null && actualValue == null)) {
                result.fail(prefix, expectedValue, actualValue);
            }
            if (expectedValue.getClass().isAssignableFrom(actualValue.getClass())) {
                if (expectedValue instanceof JSONArray) {
                    compareJSONArray(prefix, (JSONArray) expectedValue, (JSONArray) actualValue, result);
                } else if (expectedValue instanceof JSONObject) {
                    compareJSON(prefix, (JSONObject) expectedValue, (JSONObject) actualValue, result);
                } else if (!expectedValue.equals(actualValue)) {
                    result.fail(prefix, expectedValue, actualValue);
                }
            } else {
                result.fail(prefix, expectedValue, actualValue);
            }
        }
    }

    private Customization getCustomization(String path) {
        for (Customization c : customizations) {
            if (c.appliesToPath(path)) {
                return c;
            }
        }
        return null;
    }

}

方式二,使用json-patch

可扩展性或者说自定义比较较差

<dependency>
    <groupId>com.github.java-json-tools</groupId>
    <artifactId>json-patch</artifactId>
    <version>1.11</version>
</dependency>
<dependency>
    <groupId>com.jayway.jsonpath</groupId>
    <artifactId>json-path</artifactId>
    <version>2.4.0</version>
</dependency>

实操举例

public class Main {
    //与jsonStr2中orgSeqNo不一样,还有addresses中的addrType为103时的字段类型不一样
    static String jsonStr1 = "{\"orgSeqNo\":\"123123\",\"code\":200,\"person\":{\"partyId\":\"10000000001\",\"partyName\":\"张三\",\"partyCertType\":\"10100\",\"partyCertNo\":\"320925199612122314\",\"partyStatus\":\"1\",\"addresses\":[{\"addrId\":\"1\",\"partyId\":\"10000000001\",\"city\":\"苏州\",\"detailAddr\":\"相城区双塔街道33号\",\"addrType\":103,\"phone\":\"13213137625\"},{\"addrId\":\"2\",\"partyId\":\"10000000001\",\"city\":\"苏州\",\"detailAddr\":\"相城区双塔街道33号\",\"addrType\":\"101\",\"phone\":\"13213137625\"},{\"addrId\":\"3\",\"partyId\":\"10000000001\",\"city\":\"苏州\",\"detailAddr\":\"相城区双塔街道33号\",\"addrType\":\"102\",\"phone\":\"13213137625\"}]},\"message\":\"ok\"}";
    static String jsonStr2 = "{\"orgSeqNo\":\"12e9fc45c09b4a69b7aa2bbcb1313cba\",\"code\":200,\"person\":{\"partyId\":\"10000000001\",\"partyName\":\"张三\",\"partyCertType\":\"10100\",\"partyCertNo\":\"320925199612122314\",\"partyStatus\":\"1\",\"addresses\":[{\"addrId\":\"1\",\"partyId\":\"10000000001\",\"city\":\"苏州\",\"detailAddr\":\"相城区双塔街道33号\",\"addrType\":\"103\",\"phone\":\"13213137625\"},{\"addrId\":\"2\",\"partyId\":\"10000000001\",\"city\":\"苏州\",\"detailAddr\":\"相城区双塔街道33号\",\"addrType\":\"101\",\"phone\":\"13213137625\"},{\"addrId\":\"3\",\"partyId\":\"10000000001\",\"city\":\"苏州\",\"detailAddr\":\"相城区双塔街道33号\",\"addrType\":\"102\",\"phone\":\"13213137625\"}]},\"message\":\"ok\"}";
    //与jsonStr2对比,addresses数组中的顺序换了
    static String jsonStr3 = "{\"orgSeqNo\":\"12e9fc45c09b4a69b7aa2bbcb1313cba\",\"code\":200,\"person\":{\"partyId\":\"10000000001\",\"partyName\":\"张三\",\"partyCertType\":\"10100\",\"partyCertNo\":\"320925199612122314\",\"partyStatus\":\"1\",\"addresses\":[{\"addrId\":\"2\",\"partyId\":\"10000000001\",\"city\":\"苏州\",\"detailAddr\":\"相城区双塔街道33号\",\"addrType\":\"101\",\"phone\":\"13213137625\"},{\"addrId\":\"1\",\"partyId\":\"10000000001\",\"city\":\"苏州\",\"detailAddr\":\"相城区双塔街道33号\",\"addrType\":\"103\",\"phone\":\"13213137625\"},{\"addrId\":\"3\",\"partyId\":\"10000000001\",\"city\":\"苏州\",\"detailAddr\":\"相城区双塔街道33号\",\"addrType\":\"102\",\"phone\":\"13213137625\"}]},\"message\":\"ok\"}";
    //与jsonStr2对比,addresses数组中的103位数字类型
    static String jsonStr4 = "{\"orgSeqNo\":\"12e9fc45c09b4a69b7aa2bbcb1313cba\",\"code\":200,\"person\":{\"partyId\":\"10000000001\",\"partyName\":\"张三\",\"partyCertType\":\"10100\",\"partyCertNo\":\"320925199612122314\",\"partyStatus\":\"1\",\"addresses\":[{\"addrId\":\"1\",\"partyId\":\"10000000001\",\"city\":\"苏州\",\"detailAddr\":\"相城区双塔街道33号\",\"addrType\":103,\"phone\":\"13213137625\"},{\"addrId\":\"2\",\"partyId\":\"10000000001\",\"city\":\"苏州\",\"detailAddr\":\"相城区双塔街道33号\",\"addrType\":\"101\",\"phone\":\"13213137625\"},{\"addrId\":\"3\",\"partyId\":\"10000000001\",\"city\":\"苏州\",\"detailAddr\":\"相城区双塔街道33号\",\"addrType\":\"102\",\"phone\":\"13213137625\"}]},\"message\":\"ok\"}";



    public static void main(String[] args) {
        ObjectMapper mapper = new ObjectMapper();
        DocumentContext existingDoc = JsonPath.parse(jsonStr1);
        DocumentContext incomingDoc = JsonPath.parse(jsonStr4);
        existingDoc.delete("orgSeqNo");
        incomingDoc.delete("orgSeqNo");
        JsonNode existingNode = mapper.valueToTree(existingDoc.jsonString());
        JsonNode incomingNode = mapper.valueToTree(incomingDoc.jsonString());
        String diffs = JsonDiff.asJson(existingNode,incomingNode).toString();
        System.out.println("Difference: " + diffs);
    }
}

比较结果

Difference: []