【工具类】对象比较工具类实现

一、概述

ModelDiffUtil 的工具类,用于比较两个对象之间的差异,并将差异以Map的形式返回。该类的主要方法是diffToMap,它接受两个对象作为输入,并可选地接受一个忽略字段的列表。该方法首先将输入对象转换为JSON字符串,然后将JSON字符串转换为Map,最后比较两个Map的差异并返回结果。该类还包含一些辅助方法,如convertJsonToMapdoCompare,用于处理JSON到Map的转换和比较两个Map的差异。

二、方法说明

1、getDiffMap(T sourceObject, T targetObject)

将两个对象的差异转换为 Map 格式。

调用示例:

class User {
    private String name;
    private int age;

    // 构造函数、getter 和 setter 方法
}

User sourceUser = new User();
sourceUser.setName("Alice");
sourceUser.setAge(25);

User targetUser = new User();
targetUser.setName("Bob");
targetUser.setAge(30);

Map<String, Map<String, String>> diffMap = ModelDiffUtil.getDiffMap(sourceUser, targetUser);

执行结果

{
  "name": {
    "source": "Alice",
    "target": "Bob"
  },
  "age": {
    "source": "25",
    "target": "30"
  }
}

2、getDiffMap(T sourceObject, T targetObject, List<String> ignoreFields)

将两个对象的差异转换为 Map 格式,可以指定忽略的字段。

调用示例:

List<String> ignoreFields = Arrays.asList("age");
User sourceUser = new User();
sourceUser.setName("Alice");
sourceUser.setAge(25);

User targetUser = new User();
targetUser.setName("Bob");
targetUser.setAge(30);

Map<String, Map<String, String>> diffMap = ModelDiffUtil.getDiffMap(sourceUser, targetUser, ignoreFields);  

执行结果

{
  "name": {
    "source": "Alice",
    "target": "Bob"
  }
}

3、 getDiffMap(String sourceJsonStr, String targetJsonStr)

从两个 JSON 字符串中提取差异。

调用示例:

String sourceJsonStr = "{\"name\":\"Alice\",\"age\":25}";
String targetJsonStr = "{\"name\":\"Bob\",\"age\":30}";

Map<String, Map<String, String>> diffMap = ModelDiffUtil.getDiffMap(sourceJsonStr, targetJsonStr);  

执行结果

{
  "name": {
    "source": "Alice",
    "target": "Bob"
  },
  "age": {
    "source": "25",
    "target": "30"
  }
}

4、 diffToMap(String sourceJsonStr, String targetJsonStr, List<String> ignoreFields)

从两个 JSON 字符串中提取差异,可以指定忽略的字段。

调用示例

String sourceJsonStr = "{\"name\":\"Alice\",\"age\":25}";
String targetJsonStr = "{\"name\":\"Bob\",\"age\":30}";

List<String> ignoreFields = Arrays.asList("age");

Map<String, Map<String, String>> diffMap = ModelDiffUtil.getDiffMap(sourceJsonStr, targetJsonStr, ignoreFields);

执行结果

{
  "name": {
    "source": "Alice",
    "target": "Bob"
  }
}

三、内部方法
1、convertJsonToMap(Object json, String root, Map<String, Object> resultMap, List<String> ignoreFields)

  • 功能:将 JSON 对象转换为 Map ,忽略指定的字段。 - 这是一个内部辅助方法,通常不会被外部直接调用。
    2、doCompare(Map<String, Object> sourceMap, Map<String, Object> targetMap)
  • 功能:执行实际的比较操作,更新 sourceMap 以反映差异。 - 这是一个内部辅助方法,通常不会被外部直接调用。
  1. compareSourceMapWithTargetMap(Map<String, Object> sourceMap)
  • 功能:比较 sourceMaptargetMap ,处理 sourceMap 中独有的项。 - 这是一个内部辅助方法,通常不会被外部直接调用。
  1. compareTargetMapWithSourceMap(Map<String, Object> sourceMap, Map<String, Object> targetMap)
  • 功能:比较 sourceMaptargetMap ,处理 targetMap 中独有的或已更改的项。 - 这是一个内部辅助方法,通常不会被外部直接调用。

    1. processEntry(Map<String, Object> sourceMap, String key, Object value, Object targetValue)
    • 功能:处理单个条目的逻辑,根据提供的值构建差异映射或移除条目。 - 这是一个内部辅助方法,通常不会被外部直接调用。 这个工具类在需要比较对象差异并以特定格式获取结果的场景中非常有用,例如数据同步、版本控制、数据审计等。

二、完整的代码

pom依赖:

<dependency>
   <groupId>com.google.code.gson</groupId>
   <artifactId>gson</artifactId>
   <version>2.8.8</version>
</dependency>

完整代码:

import com.ecwid.consul.json.GsonFactory;
import com.google.gson.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.*;

/**
 * @author: fhey
 * @create: 2022-04-26 15:29
 * @description: 对象比较工具类
 */
@Slf4j
public class ModelDiffUtil {

    private static final Gson gson = GsonFactory.getGson();
    private final static String SOURCE_VALUE = "source";
    private final static String TARGET_VALUE = "target";
    private final static String DOT_SEPARATOR = ".";

    /**
     * 将两个对象的差异转换为Map格式。
     *
     * @param sourceObject  原始对象
     * @param targetObject 当前对象
     * @return 包含差异的Map
     */
    public static<T> Map<String, Map<String, String>> getDiffMap(T sourceObject, T targetObject) {
        return getDiffMap(sourceObject, targetObject, null);
    }

    /**
     * 将两个对象的差异转换为Map格式,可以指定忽略的字段。
     *
     * @param sourceObject  原始对象
     * @param targetObject 当前对象
     * @param ignoreFields  忽略的字段列表
     * @return 包含差异的Map
     */
    public static <T> Map<String, Map<String, String>> getDiffMap(T sourceObject, T targetObject, List<String> ignoreFields) {
        try {
            String sourceJsonStr = gson.toJson(sourceObject);
            String targetJsonStr = gson.toJson(targetObject);
            return getDiffMap(sourceJsonStr, targetJsonStr, ignoreFields);
        } catch (JsonSyntaxException e) {
            log.error("Failed to parse object to JSON", e);
            return new HashMap<>();
        }
    }

    /**
     * 从JSON字符串中提取差异。
     *
     * @param sourceJsonStr  原始JSON字符串
     * @param targetJsonStr 当前JSON字符串
     * @return 包含差异的Map
     */
    public static Map<String, Map<String, String>> getDiffMap(String sourceJsonStr, String targetJsonStr) {
        return getDiffMap(sourceJsonStr, targetJsonStr, null);
    }

    /**
     * 从JSON字符串中提取差异,可以指定忽略的字段。
     *
     * @param sourceJsonStr  原始JSON字符串
     * @param targetJsonStr 当前JSON字符串
     * @param ignoreFields   忽略的字段列表
     * @return 包含差异的Map
     */
    public static Map<String, Map<String, String>> getDiffMap(String sourceJsonStr, String targetJsonStr, List<String> ignoreFields) {
        try {
            JsonObject sourceJson = new JsonParser().parse(sourceJsonStr).getAsJsonObject();
            JsonObject targetJson = new JsonParser().parse(targetJsonStr).getAsJsonObject();
            Map<String, String> sourceMap = new LinkedHashMap<>();
            Map<String, String> targetMap = new LinkedHashMap<>();
            convertJsonToMap(sourceJson, StringUtils.EMPTY, sourceMap, ignoreFields);
            convertJsonToMap(targetJson, StringUtils.EMPTY, targetMap, ignoreFields);
            return doCompare(sourceMap, targetMap);
        } catch (JsonSyntaxException e) {
            log.error("Failed to parse JSON string", e);
            return new HashMap<>();
        }
    }

    /**
     * 将JSON对象转换为Map,忽略指定的字段。
     *
     * @param json         JSON对象
     * @param root         当前JSON路径
     * @param resultMap    存储转换结果的Map
     * @param ignoreFields 忽略的字段列表
     */
    /**
     * 将JSON对象转换为Map,忽略指定的字段。
     *
     * @param json         JSON对象
     * @param root         当前JSON路径
     * @param resultMap    存储转换结果的Map
     * @param ignoreFields 忽略的字段列表
     */
    private static void convertJsonToMap(JsonElement json, String root, Map<String, String> resultMap, List<String> ignoreFields) {
        if (json.isJsonObject()) {
            JsonObject jsonObject = json.getAsJsonObject();
            for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
                String key = entry.getKey();
                if (CollectionUtils.isNotEmpty(ignoreFields) && ignoreFields.contains(key)) {
                    continue;
                }
                JsonElement value = entry.getValue();
                String newRoot = (root.isEmpty())? key : root + DOT_SEPARATOR + key;
                if (value.isJsonObject() || value.isJsonArray()) {
                    convertJsonToMap(value, newRoot, resultMap, ignoreFields);
                } else if(value.isJsonPrimitive()){
                    resultMap.put(newRoot, value.getAsJsonPrimitive().getAsString());
                }
            }
        } else if (json.isJsonArray()) {
            JsonArray jsonArray = json.getAsJsonArray();
            for (int i = 0; i < jsonArray.size(); i++) {
                JsonElement value = jsonArray.get(i);
                String newRoot = (root.isEmpty())? "[" + i + "]" : root + "[" + i + "]";
                if (value.isJsonObject() || value.isJsonArray()) {
                    convertJsonToMap(value, newRoot, resultMap, ignoreFields);
                } else if(value.isJsonPrimitive()){
                    resultMap.put(newRoot, value.getAsJsonPrimitive().getAsString());
                }
            }
        }
    }

    /**
     * 执行实际的比较操作,返回包含差异的Map
     *
     * @param sourceMap  原始Map
     * @param targetMap 当前Map
     * @return 包含差异的Map
     */
    private static Map<String, Map<String, String>> doCompare(Map<String, String> sourceMap, Map<String, String> targetMap) {
        Map<String, Map<String, String>> diffMap = new HashMap<>();
        for (Map.Entry<String, String> entry : targetMap.entrySet()) {
            String key = entry.getKey();
            String newValue = entry.getValue();
            String oldValue = sourceMap.get(key);
            if (sourceMap.containsKey(key)) {
                if (!ObjectUtils.equals(newValue, oldValue)) {
                    addDiffMap(diffMap, key, oldValue, newValue);
                }
            } else {
                addDiffMap(diffMap, key, StringUtils.EMPTY, newValue);
            }
        }
        return diffMap;
    }


    /**
     * 将差异项添加到差异映射中。
     *
     * 此方法用于在处理两个数据集的差异时,将特定的差异项添加到一个映射中,
     * 其中每个差异项由一个键值对表示,包括源值和目标值。
     *
     * @param diffMap 保存差异项的映射,其中键是差异项的标识,值是包含源值和目标值的映射。
     * @param key 差异项的标识,用于在diffMap中作为键。
     * @param value 源对象中的值,表示差异的起始点。
     * @param targetValue 目标对象中的值,表示与源值不同的目标值。
     */
    private static void addDiffMap(Map<String, Map<String, String>> diffMap, String key, String value, String targetValue) {
        Map<String, String> diffItemMap = new HashMap<>();
        diffItemMap.put(SOURCE_VALUE, value);
        diffItemMap.put(TARGET_VALUE, targetValue);
        diffMap.put(key, diffItemMap);
    }
}

相关推荐

  1. 工具对象比较工具实现

    2024-07-17 09:06:04       20 阅读
  2. 版本比较工具VersionUtil

    2024-07-17 09:06:04       42 阅读
  3. 对象 对象实例

    2024-07-17 09:06:04       38 阅读
  4. C#实用工具

    2024-07-17 09:06:04       25 阅读
  5. webrtc 工具

    2024-07-17 09:06:04       52 阅读
  6. HttpUtils工具

    2024-07-17 09:06:04       50 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-17 09:06:04       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-17 09:06:04       72 阅读
  3. 在Django里面运行非项目文件

    2024-07-17 09:06:04       58 阅读
  4. Python语言-面向对象

    2024-07-17 09:06:04       69 阅读

热门阅读

  1. Python3 第二十四课 -- 模块

    2024-07-17 09:06:04       20 阅读
  2. 你不需要 CSS 框架

    2024-07-17 09:06:04       23 阅读
  3. 使用 RocketMQ 实现消息的顺序消费

    2024-07-17 09:06:04       26 阅读
  4. c#之修饰符知识点

    2024-07-17 09:06:04       24 阅读
  5. Conda的冲突解决艺术:在包依赖中寻找和谐

    2024-07-17 09:06:04       27 阅读
  6. zookeeper+kafka群集

    2024-07-17 09:06:04       29 阅读
  7. C++11中引入的bind绑定器和function函数对象

    2024-07-17 09:06:04       26 阅读
  8. IPython 日志秘籍:%logstate 命令全解析

    2024-07-17 09:06:04       24 阅读