一、摘要
今日推荐的是一款java中,比照两个json-diff目标是否共同的东西包 json-diff` 。他能够比照任何结构的两个json数据,而且将其中的不共同信息反馈给用户。东西还内置了许多装备能够来操控比照过程中的行为。现在现已补充大量单测,稳定性仍是比较好的。
二、布景
公司最近在重构一个中心体系,至于为什么重构原因许多,就不说明了。可是这个中心体系承载较多的线上事务。为了不影响依靠依靠该服务的应用,所以咱们重构的最中心就是彻底兼容老体系接口。
为了确保平滑上线,而且测验新体系与老体系是否共同,咱们决定体系并行一段时刻,而且在这段时刻之中验证新接口对老接口的兼容性。咱们新起一个代理服务,他会将咱们的用户流量分别转发到新老接口,然后拿到两个成果,将老接口成果直接回来;异步去比较新老成果是否契合预期,进行记录或者报警。
这样体系在经过一段时刻的测验,稳定性更高,犯错的概率更小。
因为体系都是选用http接口对外供给服务,且回来数据格局一致的是json格局。所以咱们急需一款强大的Java言语的Json比照东西来协助咱们发现新老体系的不兼容之处。
三、东西介绍
1. 介绍
json-diff 是一款功用强大的json差异发现东西,支撑任何结构的json比照,而且能够将比照成果返给用户。现在该东西更新到了 3.0.0-RC1-RELEASE
版别。最新版能够查看 版别列表 。主张运用最新版,旧版或许存在缺点。
长处:
- 轻量级:东西只依靠 fastjson2
- 精准定位:能够回来最精准且详细的信息
- 功用全面:简直掩盖任何json结构
- 高功能
2. 运用教程
2.1 快速开始
- 引入依靠
<dependency>
<groupId>cn.xiaoandcai</groupId>
<artifactId>json-diff</artifactId>
<!-- 旧版别或许存在某些缺点。版别请以maven库房最版为准。 -->
<version>${version}</version>
</dependency>
版别查看 2022-03-04 最新版别:3.0.0-RC1-RELEASE
- 开始运用
/**
* @author: codeleep
* @createTime: 2022/11/22 16:57
* @description: 运用示例
*/
public class UseExample {
public static void main(String[] args) {
String array1 = "[1, 2, 3, 4, 5]";
String array2 = "[1, 3, 9, 4, 5]";
JsonComparedOption jsonComparedOption = new JsonComparedOption().setIgnoreOrder(true);
JsonCompareResult jsonCompareResult = new DefaultJsonDifference()
.option(jsonComparedOption)
.detectDiff(JSON.parseArray(array1), JSON.parseArray(array2));
System.out.println(JSON.toJSONString(jsonCompareResult));
}
}
成果展示:
{
"defectsList": [
{
"actual": 9,
"expect": 2,
"illustrate": "The expect('2') data is inconsistent with the actual('9') data",
"travelPath": {
"abstractTravelPath": "root[]",
"actualTravelPath": "root[2]",
"expectTravelPath": "root[1]"
}
}
],
"match": false
}
东西会回来 match 表明是否经过比对。defectsList 则是比照信息。
2.2 更多装备
装备 | 类型 | 备注 |
---|---|---|
ignoreOrder | boolean | 是否比较过程中疏忽数组次序 |
mapping | Map<String, String> | 将实在字段映射到希望字段,key是实在字段name,value是希望的字段name |
ignorePath | Set<String> | 当比照的途径彻底匹配时会被越过。遇到数组运用 [] 即可。无需填入下标 |
ignoreKey | Set<String> | 比照object时。或疏忽该key。对整个json收效 |
customComparator | Map<String, Class<JsonNeat>> | 用户自定义比较器。详细说明见下文 |
在
2.0.1-RC1-RELEASE
之后版别中移除了keyFunction
装备参数。能够运用ignorePath
来替代到达相同的效果。
东西供给了四个装备,来之比照过程中一些其他的要求。东西还在积极开发中,假如有新的需求,能够给作者提一个issuse。
在开发中。许多时候比照装备共同。能够运用 JsonDiffOption
进行敞开仅有装备
3. 进阶
3.1. 大局运用固定装备
因为在设计中考虑到各线程比较装备相互独立。所以默认将装备避免在 ThreadLocal
中进行存储。但在大多数情况下,咱们在大局比较时,装备并不会产生变化。
东西供给了大局装备办法。选用的办法是静态类特点。这样也会取得更好的功能。
// 敞开并设置大局装备
JsonDiffOption.openUniqueOption();
JsonDiffOption.setGloballyUniqueOption(new JsonComparedOption());
// 不想运用时能够调用调整回线程独有模式
JsonDiffOption.closeUniqueOption();
3.2. 数组元素为目标关联
当咱们在遇到数组元素是一个目标时。如下:
[ { "date": "23日星期五", "sunrise": "06:16", "high": "高温 18.0℃" }, { "date": "24日星期六", "sunrise": "06:14", "high": "高温 21.0℃" }]
在比较时, 假如希望 date
字段共同,则以为两个目标共同。那么能够将 sunrise
, high
字段都装备到 ignorePath
中。如:
HashSet<String> ignorePath = new HashSet<>();
ignorePath.add("root[].sunrise");
ignorePath.add("root[].high");
假如只是不想关注某个字段。便是 ignorePath
正常用法。装备如上。
3.3. 字段映射
在比较两个目标时。也许因为字段名变更。导致校验不经过。这时能够运用 mapping
装备。将 实在字段称号映射至希望字段称号。在比较过程中会将
actual.mappingKey 与 expect.mappingValue 以为是应该比较的目标。详细装备如下
// mapping key 是 actual 键名
// mapping value 是 expect 键名
HashMap<String, String> mapping = new HashMap<>();
mapping.put("date", "sunrise");
3.4. 字段疏忽
假如有一些字段是想在整个json都进行疏忽的,能够运用 ignoreKey
进行大局疏忽。当然假如不想大局疏忽,可是装备了该项,仍是会被疏忽掉。
HashSet<String> ignoreKey = new HashSet<>();
ignoreKey.add("sunrise");
ignoreKey.add("high");
3.5 自定义比较器
在咱们一个大json文件下。或许遇到某些节点希望完成自定义比较。能够经过 customComparator
来进行完成。
它装备的key是一个 travelPath 。详细格局参照 ignorePath 。value 则是一个自定义比较器。关于自定义比较器需求承继对应的笼统类。而且完成详细的笼统接口。详细如下:
目标比较:
需求承继 me.codeleep.jsondiff.core.handle.array.AbstractArrayJsonNeat
而且重写以下办法。
/**
* 比较目标
* @param expect 希望的json目标
* @param actual 实践的json目标
* @return 回来比较成果
* @throws IllegalAccessException 产生反常直接抛出
*/
JsonCompareResult detectDiff(JSONObject expect, JSONObject actual);
数组比较:
需求承继 me.codeleep.jsondiff.core.handle.object.AbstractObjectJsonNeat
而且重写以下办法。
/**
* 比较数组.调用进口。需求自己去分别调用 ignoreOrder 和 keepOrder。
* @param expect 希望的json目标
* @param actual 实践的json目标
* @return 回来比较成果
*/
JsonCompareResult detectDiff(JSONArray expect, JSONArray actual);
// 疏忽次序的比较
JsonCompareResult ignoreOrder(JSONArray expect, JSONArray actual);
// 坚持次序比较
JsonCompareResult keepOrder(JSONArray expect, JSONArray actual);
根本类型比较:
根本类型指的是java根底类型的包装类型以及Number的完成类型。
需求承继 me.codeleep.jsondiff.core.handle.primitive.AbstractPrimitiveJsonNeat
而且重写以下办法。
/**
* 比较数组
* @param expect 根底类型目标
* @param actual 根底类型目标
* @return 回来比较成果
*/
JsonCompareResult detectDiff(Object expect, Object actual);
用户能够自己依据 travelPath 来决定运用何种自定义比较。三种比较器都回来 JsonCompareResult 目标作为当前节点的比较成果。关于JsonCompareResult目标。需求填入以下信息:
// 示例
JsonCompareResult result = new JsonCompareResult();
Defects defects = new Defects()
.setActual(actualDiffJson)
.setExpect(expectDiffJson)
.setTravelPath(nextTravelPath)
.setIllustrateTemplate(DATA_TYPE_INCONSISTENT, expectDiffJson.getClass().getName(), actualDiffJson.getClass().getName());
result.addDefects(defects);
假如遇到在自定义节点中,还需求运用体系自带的比较器时。
// 该值能够在上述三个笼统类中取得。但需求经自行处理
String abstractTravelPath = "root";
// 下一级是目标
TravelPath nextTravelPath = new TravelPath(abstractTravelPath, mappingKey);
// 下一级是数组
TravelPath nextTravelPath = new TravelPath(abstractTravelPath, expectIndex, actualIndex);
// 取得比较器
JsonDiffUtil.getJsonNeat(expectDiffJson, actualDiffJson, nextTravelPath);
// 履行比较取得成果
JsonCompareResult diff = jsonNeat.diff(expectDiffJson, actualDiffJson, nextTravelPath);
// 本级创立的 JsonCompareResult result 将下一级成果合并
this.result.mergeDefects(diff.getDefectsList());
能够运用上述代码获取体系自带的比较器。
自定义比较器值得注意的是: 从匹配到 travelPath 之后,依据不再接收比较操作。全部行为由用户自行定义。但东西依然预留默认的比较器给用户处理后续字段。这需求用户自行进行组合调用。
4.其他说明
前面说到东西简直能够支撑一切json成果的比照校验,而且发现差异。那它究竟能够支撑哪些呢,不知道是否契合你的需求呢?
-
目标 ✅
这是最简单的数据结构了,其中元素都以key-value构成,key是字符串,value能够是任何数据结构。
-
数组 ✅
支撑严厉次序比照和疏忽次序比照,能够细化数组元素的类型
-
根本类型 ✅
-
目标类型 ✅
该类型在比照时,能够经过ignorePath参数进行元素是否进行比较,将不关心的元素疏忽掉。当然ignoreKey也能够,但其是大局收效
-
数组类型 ✅
元素也是数组,这样就形成了多维数组,东西理论上来说支撑n维数组的比照
-
元素类型不一致 ✅
数组中,类型或许包括前面三种类型,这时东西会依照类型分类进行匹配,最后找不到的元素再反馈给用户。
-
因为json结构在单个看来,就只有目标和数组两种类型,该东西完美支撑了一切类型。
四、其他
1. 沟通群
沟通群: 710435809
2. 测验用例
现在东西测验掩盖率现已到达80%。剩下测验用例正在补全中,彻底可用于生产环境。
本文由博客一文多发平台 OpenWrite 发布!