我的编程空间,编程开发者的网络收藏夹
学习永远不晚

JSON数据的差异对比工具(Java版)

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

JSON数据的差异对比工具(Java版)

目录

背景

说明

源码

源码走读

其他


背景

        之前有类似接口diff对比,数据对比的测试需求,涉及到json格式的数据对比,调研了几个大神们分享的代码,选了一个最符合自己需求的研究了下。(可惜原文链接找不到了,原始作者看到了可以私信我下)

说明

这个对比方法,支持JsonObject和JsonArray类型的数据对比,支持:

  • 深度的对比:list变化(个数、内容)、层级结构变化
  • 字段的对比:新增、修改、删除数据可察觉,能找到对应的旧数据
  • 支持特定字段忽略对比

输出的对比结果格式为:

源码分为JsonCompareUtils, JsonAndMapSortUtils两个类,对比入口是compareTwoJson方法

核心逻辑在JsonCompareUtils类中,JsonAndMapSortUtils主要做过程中的数据排序功能,相对独立。

源码

package com.xhzyqa.transcodetest.utils;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.JSONArray;import com.alibaba.fastjson.JSONObject;import org.apache.commons.lang.ArrayUtils;import org.apache.commons.lang.StringUtils;import java.util.HashMap;import java.util.Iterator;import java.util.LinkedHashMap;import java.util.Map;import java.util.stream.Stream;public class JsonCompareUtils {    //标志位:对json报文中含有JsonArray类型的数据是否进行排序    private static boolean isSort;    private Map oldJsonToMap = new LinkedHashMap<>();    private Map newJsonToMap = new LinkedHashMap<>();    //每一个实体里的排序字段    private static Map filedNameMap = new HashMap<>();    static {        filedNameMap.put("dogs", "dogNo");        filedNameMap.put("cats", "catNo");    }    //可以跳过比对的字段//    private static String[] skipCompareFiledNameMap = {"dogAge", "catAge", "catName"};    private static String[] skipCompareFiledNameMap = {"key3"};        public String compareTwoJson(String oldJsonStr, String newJsonStr) {                convertJsonToMap(JSON.parseObject(oldJsonStr), "", false);        convertJsonToMap(JSON.parseObject(newJsonStr), "", true);        //获取比较结果        Map differenceMap = compareTwoMaps(oldJsonToMap, newJsonToMap);        String diffJsonResult = convertMapToJson(differenceMap);        return diffJsonResult;    }        private void convertJsonToMap(Object json, String root, boolean isNew) {        if (json instanceof JSONObject) {            JSONObject jsonObject = ((JSONObject) json);            Iterator iterator = jsonObject.keySet().iterator();            while (iterator.hasNext()) {                Object key = iterator.next();                Object value = jsonObject.get(key);                String newRoot = "".equals(root) ? key + "" : root + "." + key;                fillInResultMap(value, newRoot, isNew);            }        } else if (json instanceof JSONArray) {            JSONArray jsonArray = (JSONArray) json;            //将jsonArray进行排序            if (isSort) {                //需要排序                String sortEntityName = root.substring(root.lastIndexOf(".") + 1);                String sortFiledName = filedNameMap.get(sortEntityName);//需要排序 获取排序字段                if (!StringUtils.isEmpty(sortFiledName)) {                    jsonArray = JsonAndMapSortUtils.jsonArrayToSort(jsonArray, sortFiledName, true);                }            }            final JSONArray jsonArray1 = jsonArray;            Stream.iterate(0, integer -> integer + 1).limit(jsonArray1.size()).forEach(index -> {                Object value = jsonArray1.get(index);                String newRoot = "".equals(root) ? "[" + index + "]" : root + ".[" + index + "]";                fillInResultMap(value, newRoot, isNew);            });        }    }        public void fillInResultMap(Object value, String newRoot, boolean isNew) {        if (value instanceof JSONObject || value instanceof JSONArray) {            convertJsonToMap(value, newRoot, isNew);        } else {            //设置跳过比对的字段,直接不装入map            boolean check = ArrayUtils.contains(JsonCompareUtils.skipCompareFiledNameMap, newRoot);            if (!check){                if (!isNew) {                    oldJsonToMap.put(newRoot, value);                } else {                    newJsonToMap.put(newRoot, value);                }            }        }    }        private Map compareTwoMaps(Map oldJsonMap, Map newJsonMap) {        //1.将newJsonMap的不同数据装进oldJsonMap,同时删除oldJsonMap中与newJsonMap相同的数据        newJsonMap.forEach((k, v) -> {            Map differenceMap = new HashMap<>();            String lastFieldKey = k.substring(k.lastIndexOf(".") + 1);//            boolean check = ArrayUtils.contains(JsonCompareUtils.skipCompareFiledNameMap, lastFieldKey);//            if (!check){            if (oldJsonMap.containsKey(k)) {//                boolean check = ArrayUtils.contains(JsonCompareUtils.skipCompareFiledNameMap, lastFieldKey);                Object oldValue = oldJsonMap.get(k);                if (v.equals(oldValue)) {                    oldJsonMap.remove(k);                } else {                    differenceMap.put("oldValue", oldValue);                    differenceMap.put("newValue", v);                    oldJsonMap.put(k, differenceMap);                }            } else {                differenceMap.put("oldValue", "no exists " + k);                differenceMap.put("newValue", v);                oldJsonMap.put(k, differenceMap);            }//            }else {//                oldJsonMap.remove(k);//            }        });        //2.统一oldJsonMap中newMap不存在的数据的数据结构,便于解析        oldJsonMap.forEach((k, v) -> {            String lastFieldKey = k.substring(k.lastIndexOf(".") + 1);//            boolean check = ArrayUtils.contains(JsonCompareUtils.skipCompareFiledNameMap, lastFieldKey);//            if (!check && !(v instanceof Map)) {            if (!(v instanceof Map)) {                Map differenceMap = new HashMap<>();                differenceMap.put("oldValue", v);                differenceMap.put("newValue", "no exists " + k);                oldJsonMap.put(k, differenceMap);            }        });        return oldJsonMap;    }        private String convertMapToJson(Map map) {        JSONObject resultJSONObject = new JSONObject();        for (Iterator> it = map.entrySet().iterator(); it.hasNext(); ) {            Map.Entry item = it.next();            String key = item.getKey();            Object value = item.getValue();            String[] paths = key.split("\\.");            int i = 0;            Object remarkObject = null;//用於深度標識對象            int indexAll = paths.length - 1;            while (i <= paths.length - 1) {                String path = paths[i];                if (i == 0) {                    //初始化对象标识                    if (resultJSONObject.containsKey(path)) {                        remarkObject = resultJSONObject.get(path);                    } else {                        if (indexAll > i) {if (paths[i + 1].matches("\\[[0-9]+\\]")) {    remarkObject = new JSONArray();} else {    remarkObject = new JSONObject();}resultJSONObject.put(path, remarkObject);                        } else {resultJSONObject.put(path, value);                        }                    }                    i++;                    continue;                }                if (path.matches("\\[[0-9]+\\]")) {//匹配集合对象                    int startIndex = path.lastIndexOf("[");                    int endIndext = path.lastIndexOf("]");                    int index = Integer.parseInt(path.substring(startIndex + 1, endIndext));                    if (indexAll > i) {                        if (paths[i + 1].matches("\\[[0-9]+\\]")) {while (((JSONArray) remarkObject).size() <= index) {    if (((JSONArray) remarkObject).size() == index) {        ((JSONArray) remarkObject).add(index, new JSONArray());    } else {        ((JSONArray) remarkObject).add(null);    }}                        } else {while (((JSONArray) remarkObject).size() <= index) {    if (((JSONArray) remarkObject).size() == index) {        ((JSONArray) remarkObject).add(index, new JSONObject());    } else {        ((JSONArray) remarkObject).add(null);    }}                        }                        remarkObject = ((JSONArray) remarkObject).get(index);                    } else {                        while (((JSONArray) remarkObject).size() <= index) {if (((JSONArray) remarkObject).size() == index) {    ((JSONArray) remarkObject).add(index, value);} else {    ((JSONArray) remarkObject).add(null);}                        }                    }                } else {                    if (indexAll > i) {                        if (paths[i + 1].matches("\\[[0-9]+\\]")) {if (!((JSONObject) remarkObject).containsKey(path)) {    ((JSONObject) remarkObject).put(path, new JSONArray());}                        } else {if (!((JSONObject) remarkObject).containsKey(path)) {    ((JSONObject) remarkObject).put(path, new JSONObject());}                        }                        remarkObject = ((JSONObject) remarkObject).get(path);                    } else {                        ((JSONObject) remarkObject).put(path, value);                    }                }                i++;            }        }        return JSON.toJSONString(resultJSONObject);    }    public boolean isSort() {        return isSort;    }    public void setSort(boolean sort) {        isSort = sort;    }    public static void main(String[] args) {        String oldStr = "{key1:'aaa',key2:'bbb'}";        String newStr = "{key1:'aaa',key2:'bbb',key3:'c'}";        System.out.println(new JsonCompareUtils().compareTwoJson(oldStr, newStr));        System.out.println("\n========测试复杂json的比对============");    }    }
package com.xhzyqa.transcodetest.utils;import com.alibaba.fastjson.JSONArray;import com.alibaba.fastjson.JSONObject;import sun.misc.ASCIICaseInsensitiveComparator;import java.util.*;import java.util.function.Function;import java.util.stream.Collectors;public class JsonAndMapSortUtils {        public static  List mapByKeyToSort(Map map , final Comparator keySort){        List> entryList = new ArrayList>(map.entrySet());        Collections.sort(entryList, new Comparator>() {            public int compare(Map.Entry o1, Map.Entry o2) {                return keySort.compare(o1.getKey(),o2.getKey());            }        });        //return (Map)entryList.stream().collect(Collectors.toMap(Map.Entry::getKey, Function.identity(), (key1, key2) -> key2));        Map afterToSortMap = new HashMap<>();                System.out.println("排序=====");        entryList.forEach(m->{            System.out.println(m.getKey()+"===>"+m.getValue());        });        return entryList;    }        public static JSONArray jsonArrayToSort(JSONArray jsonArray,final String fildName,final boolean isAsc){        JSONArray afterSortJsonArray = new JSONArray();        List objectList = new ArrayList();        jsonArray.forEach(obj ->{            objectList.add((JSONObject)obj);        });        Collections.sort(objectList, new Comparator() {            @Override            public int compare(JSONObject o1, JSONObject o2) {                String fildValueA = o1.getString(fildName);                String fildValueB = o2.getString(fildName);                if (isAsc)                    return fildValueA.compareTo(fildValueB);                return fildValueB.compareTo(fildValueA);            }        });        objectList.forEach(obj->{            afterSortJsonArray.add(obj);        });        return afterSortJsonArray;    }        public static Map getMapData(){        LinkedHashMap map = new LinkedHashMap<>();        map.put("key1","麦兜");        map.put("key3","贝塔");        map.put("key5","酥妮");        map.put("key2","小H");        map.put("key4","小O");        return map;    }        public static JSONArray getJsonArrayData(){        JSONArray jsonArray = new JSONArray();        JSONObject jsonObject1 = new JSONObject();        jsonObject1.put("userId","1001");        jsonObject1.put("name","麦兜");        jsonArray.add(jsonObject1);        JSONObject jsonObject3 = new JSONObject();        jsonObject3.put("userId","1003");        jsonObject3.put("name","酥妮");        jsonArray.add(jsonObject3);        JSONObject jsonObject2 = new JSONObject();        jsonObject2.put("userId","1002");        jsonObject2.put("name","贝塔");        jsonArray.add(jsonObject2);        return jsonArray;    }    public static void main(String[] args) {        Map map = JsonAndMapSortUtils.getMapData();        JSONArray jsonArray = JsonAndMapSortUtils.getJsonArrayData();        List afterSortMap = JsonAndMapSortUtils.mapByKeyToSort(map,new ASCIICaseInsensitiveComparator());        JSONArray afterSortJsonArray_isAsc = JsonAndMapSortUtils.jsonArrayToSort(jsonArray,"userId",true);        JSONArray afterSortJsonArray_noAsc = JsonAndMapSortUtils.jsonArrayToSort(jsonArray,"userId",false);        System.out.println("map排序前:"+map);        System.out.println("map排序后:"+afterSortMap+"\n");        System.out.println("JsonArray排序前:"+jsonArray);        System.out.println("JsonArray排序后==》升序:"+afterSortJsonArray_isAsc);        System.out.println("JsonArray排序后==》降序:"+afterSortJsonArray_noAsc);    }}

源码走读

整个源码调用链路如下图,简单来说过程就是:object拆分解析-新旧数据逐个对比-结果信息组装三个步骤

其他

原始代码中有些小bug,已修复。目前这个工具主要被我拿来用在了一个接口数据对比工具中,来检测迭代前后的接口协议数据变更,以完善迭代变更范围来确认测试范围

来源地址:https://blog.csdn.net/hi_bigbai/article/details/128162687

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

JSON数据的差异对比工具(Java版)

下载Word文档到电脑,方便收藏和打印~

下载Word文档

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录