java對(duì)JSON字符串差異化對(duì)比分析
java JSON字符串差異化對(duì)比


需求是要對(duì)比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
使用此方法的好處是可以自定義一些對(duì)比規(guī)則(強(qiáng)烈推薦)
- 首先引入pom依賴
<dependency>
<groupId>org.skyscreamer</groupId>
<artifactId>jsonassert</artifactId>
<version>1.5.1</version>
</dependency>
- 編寫代碼
public class Main {
//與jsonStr2中orgSeqNo不一樣,還有addresses中的addrType為103時(shí)的字段類型不一樣
static String jsonStr1 = "{\"orgSeqNo\":\"123123\",\"code\":200,\"person\":{\"partyId\":\"10000000001\",\"partyName\":\"張三\",\"partyCertType\":\"10100\",\"partyCertNo\":\"320925199612122314\",\"partyStatus\":\"1\",\"addresses\":[{\"addrId\":\"1\",\"partyId\":\"10000000001\",\"city\":\"蘇州\",\"detailAddr\":\"相城區(qū)雙塔街道33號(hào)\",\"addrType\":103,\"phone\":\"13213137625\"},{\"addrId\":\"2\",\"partyId\":\"10000000001\",\"city\":\"蘇州\",\"detailAddr\":\"相城區(qū)雙塔街道33號(hào)\",\"addrType\":\"101\",\"phone\":\"13213137625\"},{\"addrId\":\"3\",\"partyId\":\"10000000001\",\"city\":\"蘇州\",\"detailAddr\":\"相城區(qū)雙塔街道33號(hào)\",\"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\":\"相城區(qū)雙塔街道33號(hào)\",\"addrType\":\"103\",\"phone\":\"13213137625\"},{\"addrId\":\"2\",\"partyId\":\"10000000001\",\"city\":\"蘇州\",\"detailAddr\":\"相城區(qū)雙塔街道33號(hào)\",\"addrType\":\"101\",\"phone\":\"13213137625\"},{\"addrId\":\"3\",\"partyId\":\"10000000001\",\"city\":\"蘇州\",\"detailAddr\":\"相城區(qū)雙塔街道33號(hào)\",\"addrType\":\"102\",\"phone\":\"13213137625\"}]},\"message\":\"ok\"}";
//與jsonStr2對(duì)比,addresses數(shù)組中的順序換了
static String jsonStr3 = "{\"orgSeqNo\":\"12e9fc45c09b4a69b7aa2bbcb1313cba\",\"code\":200,\"person\":{\"partyId\":\"10000000001\",\"partyName\":\"張三\",\"partyCertType\":\"10100\",\"partyCertNo\":\"320925199612122314\",\"partyStatus\":\"1\",\"addresses\":[{\"addrId\":\"2\",\"partyId\":\"10000000001\",\"city\":\"蘇州\",\"detailAddr\":\"相城區(qū)雙塔街道33號(hào)\",\"addrType\":\"101\",\"phone\":\"13213137625\"},{\"addrId\":\"1\",\"partyId\":\"10000000001\",\"city\":\"蘇州\",\"detailAddr\":\"相城區(qū)雙塔街道33號(hào)\",\"addrType\":\"103\",\"phone\":\"13213137625\"},{\"addrId\":\"3\",\"partyId\":\"10000000001\",\"city\":\"蘇州\",\"detailAddr\":\"相城區(qū)雙塔街道33號(hào)\",\"addrType\":\"102\",\"phone\":\"13213137625\"}]},\"message\":\"ok\"}";
//與jsonStr2對(duì)比,addresses數(shù)組中的103位數(shù)字類型
static String jsonStr4 = "{\"orgSeqNo\":\"12e9fc45c09b4a69b7aa2bbcb1313cba\",\"code\":200,\"person\":{\"partyId\":\"10000000001\",\"partyName\":\"張三\",\"partyCertType\":\"10100\",\"partyCertNo\":\"320925199612122314\",\"partyStatus\":\"1\",\"addresses\":[{\"addrId\":\"1\",\"partyId\":\"10000000001\",\"city\":\"蘇州\",\"detailAddr\":\"相城區(qū)雙塔街道33號(hào)\",\"addrType\":103,\"phone\":\"13213137625\"},{\"addrId\":\"2\",\"partyId\":\"10000000001\",\"city\":\"蘇州\",\"detailAddr\":\"相城區(qū)雙塔街道33號(hào)\",\"addrType\":\"101\",\"phone\":\"13213137625\"},{\"addrId\":\"3\",\"partyId\":\"10000000001\",\"city\":\"蘇州\",\"detailAddr\":\"相城區(qū)雙塔街道33號(hào)\",\"addrType\":\"102\",\"phone\":\"13213137625\"}]},\"message\":\"ok\"}";
public static void main(String[] args) {
//aasdasdbc為過濾的節(jié)點(diǎn),隨意指定
Customization[] customizations = {new Customization("aasdasdbc",(o1, o2) -> { return true;})};
JSONCompareResult result = null;
JSONCompareResult result1 = null;
JSONCompareResult result2 = null;
try {
// JSONCompareMode.NON_EXTENSIBLE 不可擴(kuò)展模式,可忽略數(shù)組排序
// 寬大模式(LENIENT) 可擴(kuò)展,數(shù)組不用排序
// 嚴(yán)格模式(STRICT) 不可擴(kuò)展, 數(shù)組嚴(yán)格排序
// 嚴(yán)格排序模式(STRICT_ORDER) 如字面意思,可擴(kuò)展
// 擴(kuò)展的意思是已有的[1,23,45]和[1,23,45,6]在STRICT_ORDER是可以的
// 使用自定義比較規(guī)則
result = JSONCompare.compareJSON(jsonStr1, jsonStr2, new MyCustomComparator(JSONCompareMode.NON_EXTENSIBLE, customizations));
// 過濾orgSeqNo根節(jié)點(diǎn)字段
result1 = JSONCompare.compareJSON(jsonStr1, jsonStr3, new CustomComparator(JSONCompareMode.NON_EXTENSIBLE,
Customization.customization("orgSeqNo", (o1, o2) -> {
return true;
})));
// 過濾orgSeqNo根節(jié)點(diǎn),以及過濾person根節(jié)點(diǎn)下的addresses數(shù)組節(jié)點(diǎn)的addrType節(jié)點(diǎn)字段
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);
}
}
}
- 對(duì)比效果
兩者相等
person.addresses[addrId=1].addrType
Expected: 103
got: 103
兩者相等
- 上述自定義的過濾規(guī)則
public class MyCustomComparator extends CustomComparator {
private final Collection<Customization> customizations;
public MyCustomComparator(JSONCompareMode mode, Customization[] customizations) {
super(mode);
this.customizations = Arrays.asList(customizations);
}
//比較器默認(rèn)調(diào)用此方法,如果要實(shí)現(xiàn)復(fù)雜邏輯,可以重寫
@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 {
// 過濾某些節(jié)點(diǎn)字段
if (prefix.indexOf("orgSeqNo") != -1 || prefix.indexOf("addrType") != -1) {
return;
}
// todo 可以設(shè)置一些復(fù)雜的比較,例如某個(gè)字段的數(shù)值字符串和數(shù)值可忽略,小數(shù)和某些整數(shù)可忽略
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
可擴(kuò)展性或者說自定義比較較差
<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>
實(shí)操舉例
public class Main {
//與jsonStr2中orgSeqNo不一樣,還有addresses中的addrType為103時(shí)的字段類型不一樣
static String jsonStr1 = "{\"orgSeqNo\":\"123123\",\"code\":200,\"person\":{\"partyId\":\"10000000001\",\"partyName\":\"張三\",\"partyCertType\":\"10100\",\"partyCertNo\":\"320925199612122314\",\"partyStatus\":\"1\",\"addresses\":[{\"addrId\":\"1\",\"partyId\":\"10000000001\",\"city\":\"蘇州\",\"detailAddr\":\"相城區(qū)雙塔街道33號(hào)\",\"addrType\":103,\"phone\":\"13213137625\"},{\"addrId\":\"2\",\"partyId\":\"10000000001\",\"city\":\"蘇州\",\"detailAddr\":\"相城區(qū)雙塔街道33號(hào)\",\"addrType\":\"101\",\"phone\":\"13213137625\"},{\"addrId\":\"3\",\"partyId\":\"10000000001\",\"city\":\"蘇州\",\"detailAddr\":\"相城區(qū)雙塔街道33號(hào)\",\"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\":\"相城區(qū)雙塔街道33號(hào)\",\"addrType\":\"103\",\"phone\":\"13213137625\"},{\"addrId\":\"2\",\"partyId\":\"10000000001\",\"city\":\"蘇州\",\"detailAddr\":\"相城區(qū)雙塔街道33號(hào)\",\"addrType\":\"101\",\"phone\":\"13213137625\"},{\"addrId\":\"3\",\"partyId\":\"10000000001\",\"city\":\"蘇州\",\"detailAddr\":\"相城區(qū)雙塔街道33號(hào)\",\"addrType\":\"102\",\"phone\":\"13213137625\"}]},\"message\":\"ok\"}";
//與jsonStr2對(duì)比,addresses數(shù)組中的順序換了
static String jsonStr3 = "{\"orgSeqNo\":\"12e9fc45c09b4a69b7aa2bbcb1313cba\",\"code\":200,\"person\":{\"partyId\":\"10000000001\",\"partyName\":\"張三\",\"partyCertType\":\"10100\",\"partyCertNo\":\"320925199612122314\",\"partyStatus\":\"1\",\"addresses\":[{\"addrId\":\"2\",\"partyId\":\"10000000001\",\"city\":\"蘇州\",\"detailAddr\":\"相城區(qū)雙塔街道33號(hào)\",\"addrType\":\"101\",\"phone\":\"13213137625\"},{\"addrId\":\"1\",\"partyId\":\"10000000001\",\"city\":\"蘇州\",\"detailAddr\":\"相城區(qū)雙塔街道33號(hào)\",\"addrType\":\"103\",\"phone\":\"13213137625\"},{\"addrId\":\"3\",\"partyId\":\"10000000001\",\"city\":\"蘇州\",\"detailAddr\":\"相城區(qū)雙塔街道33號(hào)\",\"addrType\":\"102\",\"phone\":\"13213137625\"}]},\"message\":\"ok\"}";
//與jsonStr2對(duì)比,addresses數(shù)組中的103位數(shù)字類型
static String jsonStr4 = "{\"orgSeqNo\":\"12e9fc45c09b4a69b7aa2bbcb1313cba\",\"code\":200,\"person\":{\"partyId\":\"10000000001\",\"partyName\":\"張三\",\"partyCertType\":\"10100\",\"partyCertNo\":\"320925199612122314\",\"partyStatus\":\"1\",\"addresses\":[{\"addrId\":\"1\",\"partyId\":\"10000000001\",\"city\":\"蘇州\",\"detailAddr\":\"相城區(qū)雙塔街道33號(hào)\",\"addrType\":103,\"phone\":\"13213137625\"},{\"addrId\":\"2\",\"partyId\":\"10000000001\",\"city\":\"蘇州\",\"detailAddr\":\"相城區(qū)雙塔街道33號(hào)\",\"addrType\":\"101\",\"phone\":\"13213137625\"},{\"addrId\":\"3\",\"partyId\":\"10000000001\",\"city\":\"蘇州\",\"detailAddr\":\"相城區(qū)雙塔街道33號(hào)\",\"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);
}
}
比較結(jié)果
Difference: []
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
springboot構(gòu)造樹形結(jié)構(gòu)數(shù)據(jù)并查詢的方法
本文主要介紹了springboot怎樣構(gòu)造樹形結(jié)構(gòu)數(shù)據(jù)并查詢,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-11-11
Spring中的@RestControllerAdvice注解使用解析
這篇文章主要介紹了Spring中的@RestControllerAdvice注解使用解析,@RestControllerAdvice?是?Spring?框架中一個(gè)用于統(tǒng)一處理控制器異常和返回結(jié)果的注解,它可以被用來定義全局異常處理程序和全局響應(yīng)結(jié)果處理程序,需要的朋友可以參考下2024-01-01
Java8新特性之泛型的目標(biāo)類型推斷_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
泛型是Java SE 1.5的新特性,泛型的本質(zhì)是參數(shù)化類型,也就是說所操作的數(shù)據(jù)類型被指定為一個(gè)參數(shù)。下面通過本文給分享Java8新特性之泛型的目標(biāo)類型推斷,感興趣的朋友參考下吧2017-06-06
Java?static靜態(tài)與非靜態(tài)訪問規(guī)則解析及避坑指南
Java靜態(tài)和非靜態(tài)成員變量初始化過程解析是Java語言中一個(gè)非常重要的概念,這篇文章主要介紹了Java?static靜態(tài)與非靜態(tài)訪問規(guī)則解析及避坑指南的相關(guān)資料,需要的朋友可以參考下2026-05-05
提示:Decompiled.class file,bytecode version如何解決
在處理Decompiled.classfile和bytecodeversion問題時(shí),通過修改Maven配置文件,添加阿里云鏡像并去掉默認(rèn)鏡像,解決了下載源的問題,同時(shí),檢查并修改了依賴版本,確保了問題的解決2024-12-12

