All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.fastobject.diff.AbstractObjectDiff Maven / Gradle / Ivy

The newest version!
package com.fastobject.diff;


import java.time.format.DateTimeFormatter;
import org.apache.commons.lang.StringUtils;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Created by colinsu
 *
 */
public abstract class AbstractObjectDiff {

    public static final Field[] EMPTY_FIELD_ARRAY = {};

    protected abstract String genDiffStr(Object sourceObject, Object targetObject) throws Exception;

    public static String genChineseDiffStr(Object sourceObject, Object targetObject) throws Exception {
        List diffWappers = generateDiff(sourceObject, targetObject);
        return DiffUtils.genDiffStr(diffWappers);
    }

    public static List generateDiff(Object sourceObject, Object targetObject) throws Exception {
        return generateDiff("", "", sourceObject, targetObject);
    }

    private static List generateDiff(String path, String cnName, Object sourceObject, Object targetObject)
        throws Exception {
        List diffWappers = new ArrayList<>();

        if (sourceObject == null && targetObject == null) {
            return null;
        }

        if (sourceObject == null || targetObject == null) {
            DiffWapper diffWapper = DiffUtils
                .getDiffWapper(path, cnName, (sourceObject == null ? null : getObjectString(sourceObject)),
                    targetObject == null ? null : getObjectString(targetObject));
            diffWappers.add(diffWapper);
            return diffWappers;
        }

        //先判断object类型
        if (!sourceObject.getClass().getName().equals(targetObject.getClass().getName())) {
            return null;
        }

        if (sourceObject.hashCode() == targetObject.hashCode()) {
            return null;
        }

        Field[] fields = getAllFields(sourceObject.getClass());

        for (int i = 0; i < fields.length; i++) {
            final Field field = fields[i];
            Class type = field.getType();
            String newPath = path + "/" + field.getName();
            String nameCn = newPath;
            field.setAccessible(true);
            if (field.isAnnotationPresent(DiffLog.class)) {
                DiffLog logVo = field.getAnnotation(DiffLog.class);
                if (cnName == null || cnName.equals("")) {
                    nameCn = logVo.name();
                } else {
                    nameCn = cnName + "." + logVo.name();
                }
                if (logVo.ignore()){
                    continue;
                }
            }else{
                continue;
            }
            if (Collection.class.isAssignableFrom(type)) {
                //先判断一下集合
                List oldList = (List) field.get(sourceObject);
                List newList = (List) field.get(targetObject);
                Map oldFilterMap = new HashMap<>();
                Map newFilterMap = new HashMap<>();
                Class genricClass = null;
                if (field.getGenericType() instanceof ParameterizedType) {
                    // 获取泛型 Class
                    genricClass = (Class) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0];
                }
                if (genricClass == null) {
                    continue;
                }
                Field[] collFields = getAllFields(genricClass);
                Field keyField = null;
                String keyCnName = "";
                for (int j = 0; j < collFields.length; j++) {
                    if (collFields[j].isAnnotationPresent(DiffLogKey.class)) {
                        keyField = collFields[j];
                        DiffLogKey keyFieldAnnotation = keyField.getAnnotation(DiffLogKey.class);
                        keyCnName = keyFieldAnnotation.name();
                        break;
                    }
                }
                if (keyField == null){
                    continue;
                }
                keyField.setAccessible(true);
                if (newList != null) {
                    for (Object o : newList) {
                        Object o1 = keyField.get(o);
                        newFilterMap.put(o1, o);
                    }
                }
                if (oldList != null) {
                    for (Object old : oldList) {
                        Object o2 = keyField.get(old);
                        oldFilterMap.put(o2, old);
                    }
                }
                Set oldKeySets = oldFilterMap.keySet();
                Set newKeySets = newFilterMap.keySet();
                Set resultSet = new HashSet<>();
                resultSet.clear();
                resultSet.addAll(oldKeySets);
                resultSet.addAll(newKeySets);
                //取两个之间的并集,然后统一输出
                for (Object result : resultSet) {
                    Object oldOb = oldFilterMap.get(result);
                    Object newOb = newFilterMap.get(result);
                    String oBPath = newPath + "/" + (result == null ? "null" : result.toString());
                    String oBcnName = nameCn + "." + keyCnName + "[" + (result == null ? "null" : result.toString()) + "]";
                    List collectDiff = generateDiff(oBPath, oBcnName, oldOb, newOb);
                    if (collectDiff != null) {
                        diffWappers.addAll(collectDiff);
                    }
                }
            } else {
                //判断是否java内部类
                if (isJavaClass(type)){
                    DiffWapper diffWapper = generateOneDiffs(newPath, nameCn, field, sourceObject, targetObject);
                    if (diffWapper != null) {
                        diffWappers.add(diffWapper);
                    }
                } else {
                    //如自定义bean则走递归方法
                    List collectDiff = generateDiff(newPath, nameCn,
                        field.get(sourceObject), field.get(targetObject));
                    if (collectDiff != null) {
                        diffWappers.addAll(collectDiff);
                    }
                }
            }

        }
        return diffWappers;
    }



    private static DiffWapper generateOneDiffs(String path, String nameCn, Field field, Object source, Object target)
        throws Exception {
        //判断是普通Object还是Collection
        //过滤一些不需要的key
        //Collection需要根据某个key进行排序,然后比较
        DiffUtils diffUtils = new DiffUtils();
        String typeName = field.getType().getName();
        Class type = field.getType();
        field.setAccessible(true);
        DiffLog logVo = field.getAnnotation(DiffLog.class);
        String dateFormat = "";
        if (logVo != null) {
            dateFormat = logVo.dateFormat();
            if (logVo.ignore()){
                return null;
            }
        }
        if ("java.lang.String".equals(typeName)) {
            String oldStr = (String) field.get(source);
            String newStr = (String) field.get(target);
            return diffUtils.get(path, nameCn, oldStr, newStr);
        } else if ("java.sql.Timestamp".equals(typeName)) {
            DateFormat format =
                new SimpleDateFormat(StringUtils.isBlank(dateFormat) ? "yyyy-MM-dd HH:mm:ss" : dateFormat);
            java.sql.Timestamp newTime = (java.sql.Timestamp) field.get(target);
            java.sql.Timestamp oldTime = (java.sql.Timestamp) field.get(source);
            String newTempTimeStr = "";
            String oldTimeTimeStr = "";
            if (newTime != null) {
                newTempTimeStr = format.format(newTime);
            }
            if (oldTime != null) {
                oldTimeTimeStr = format.format(oldTime);
            }
            if (oldTime == newTime && oldTime == null) {
                return null;
            }
            if (oldTime == null || newTime == null) {
                return DiffUtils.getDiffWapper(path, nameCn, oldTime==null ?null:oldTimeTimeStr, newTime==null?null: newTempTimeStr);
            }

            if (!StringUtils.equals(newTempTimeStr, oldTimeTimeStr)) {
                return DiffUtils.getDiffWapper(path, nameCn, format.format(oldTime), format.format(newTime));
            }
        } else if ("java.lang.Long".equals(typeName) || Long.TYPE == type) {
            Long oldValue = (Long) field.get(source);
            Long newValue = (Long) field.get(target);
            return diffUtils.get(path, nameCn, oldValue, newValue);

        } else if ("java.lang.Integer".equals(typeName) || Integer.TYPE == type) {
            Integer oldValue =(Integer) field.get(source);
            Integer newValue = (Integer) field.get(target);
            return diffUtils.get(path, nameCn, oldValue, newValue);

        } else if ("java.lang.Boolean".equals(typeName) || Boolean.TYPE == type) {
            Boolean oldValue = (Boolean)field.get(source);
            Boolean newValue = (Boolean)field.get(target);
            return diffUtils.get(path, nameCn, oldValue, newValue);

        } else if ("java.math.BigDecimal".equals(typeName)) {
            BigDecimal oldValue = (BigDecimal)field.get(source);
            BigDecimal newValue = (BigDecimal)field.get(target) ;
            if (oldValue!=null && newValue!=null && oldValue.compareTo(newValue) == 0){
                newValue = oldValue;
            }
            return diffUtils.get(path, nameCn, oldValue, newValue);
        } else if ("java.lang.Byte".equals(typeName) || Byte.TYPE == type) {
            //预留不处理
            Byte oldValue = (Byte) field.get(source);
            Byte newValue = (Byte) field.get(target);
            if (oldValue!=null && newValue!=null && oldValue.compareTo(newValue) == 0){
                newValue = oldValue;
            }
            return diffUtils.get(path, nameCn, oldValue, newValue);
        } else if ("java.lang.Short".equals(typeName) || Short.TYPE == type) {
            Short oldValue = (Short) field.get(source);
            Short newValue = (Short) field.get(target);
            if (oldValue!=null && newValue!=null && oldValue.compareTo(newValue) == 0){
                newValue = oldValue;
            }
            return diffUtils.get(path, nameCn, oldValue, newValue);
            //预留不处理 有需要在处理
        } else if ("java.lang.Float".equals(typeName) || Float.TYPE == type) {
            Float oldValue = field.getFloat(source);
            Float newValue = field.getFloat(target);
            return diffUtils.get(path, nameCn, oldValue, newValue);

        } else if ("java.lang.Double".equals(typeName) || Double.TYPE == type) {
            String oldValue = field.get(source) == null? null :String.valueOf(field.get(source));
            String newValue =  field.get(target) == null ? null :String.valueOf(field.get(target));
            return diffUtils.get(path, nameCn, oldValue, newValue);

        }
        else if ("java.util.Date".equals(typeName)) {
            DateFormat format = new SimpleDateFormat(StringUtils.isBlank(dateFormat) ? "yyyy-MM-dd" : dateFormat);
            java.util.Date newTime = (java.util.Date) field.get(target);
            java.util.Date oldTime = (java.util.Date) field.get(source);
            String newTempTimeStr = "";
            String oldTimeTimeStr = "";
            if (newTime != null) {
                newTempTimeStr = format.format(newTime);
            }
            if (oldTime != null) {
                oldTimeTimeStr = format.format(oldTime);
            }
            if (oldTime == newTime && oldTime == null) {
                return null;
            }
            if (oldTime == null || newTime == null) {
                return DiffUtils.getDiffWapper(path, nameCn, oldTime==null ?null:oldTimeTimeStr, newTime==null?null: newTempTimeStr);
            }
            if (!StringUtils.equals(newTempTimeStr, oldTimeTimeStr)) {
                return DiffUtils.getDiffWapper(path, nameCn, oldTimeTimeStr, newTempTimeStr);
            }
        }
        else if ("java.time.LocalDateTime".equals(typeName)) {
            DateTimeFormatter format =  DateTimeFormatter.ofPattern(StringUtils.isBlank(dateFormat) ? "yyyy-MM-dd hh:mm:ss" : dateFormat);
            java.time.LocalDateTime newTime = (java.time.LocalDateTime) field.get(target);
            java.time.LocalDateTime oldTime = (java.time.LocalDateTime) field.get(source);
            String newTempTimeStr = "";
            String oldTimeTimeStr = "";
            if (newTime != null) {
                newTempTimeStr = format.format(newTime);
            }
            if (oldTime != null) {
                oldTimeTimeStr = format.format(oldTime);
            }
            if (oldTime == newTime && oldTime == null) {
                return null;
            }
            if (oldTime == null || newTime == null) {
                return DiffUtils.getDiffWapper(path, nameCn, oldTime==null ?null:oldTimeTimeStr, newTime==null?null: newTempTimeStr);
            }
            if (!StringUtils.equals(newTempTimeStr, oldTimeTimeStr)) {
                return DiffUtils.getDiffWapper(path, nameCn, oldTimeTimeStr, newTempTimeStr);
            }
        }
        return null;
    }


    private static String getObjectString(Object source) throws Exception {
        if (source == null) {
            return "";
        }
        List logList = new ArrayList<>();
        Field[] fields = getAllFields(source.getClass());
        for (int i = 0; i < fields.length; i++) {
            String logStr = "";
            Field field = fields[i];
            String typeName = field.getType().getName();
            field.setAccessible(true);
            DiffLog logVo = field.getAnnotation(DiffLog.class);
            String nameCn = field.getName();
            String dateFormat = "";
            if (logVo != null) {
                nameCn = logVo.name();
                dateFormat = logVo.dateFormat();
            } else {
                continue;
            }
            if ("java.lang.String".equals(typeName)) {
                String oldStr = (String) field.get(source);
                logStr = "[" + nameCn + "]=" + oldStr + " ";
                logList.add(logStr);
            } else if ("java.util.Date".equals(typeName)) {
                DateFormat format =
                    new SimpleDateFormat(StringUtils.isBlank(dateFormat) ? "yyyy-MM-dd HH:mm:ss" : dateFormat);
                java.util.Date oldTime = (java.util.Date) field.get(source);
                if (oldTime != null) {
                    logStr = "[" + nameCn + "]=" + format.format(oldTime) + " ";
                    logList.add(logStr);
                }
            } else {
                Object oldValue = (Object) field.get(source);
                logStr = "[" + nameCn + "]=" + (oldValue == null ? "null" : oldValue.toString()) + " ";
                logList.add(logStr);
            }


        }
        return StringUtils.join(logList.iterator(),",").trim();

    }


    public static boolean isJavaClass(Class clz) {
        return clz != null && clz.getClassLoader() == null;
    }

    /**
     * org.apache.commons.lang3.reflect.FieldUtils.getAllFields(),version 3.13.0
     */
    private static Field[] getAllFields(final Class cls) {
        if (cls == null)
            throw new NullPointerException("cls");
        final List allFields = new ArrayList<>();
        Class currentClass = cls;
        while (currentClass != null) {
            final Field[] declaredFields = currentClass.getDeclaredFields();
            Collections.addAll(allFields, declaredFields);
            currentClass = currentClass.getSuperclass();
        }
        return allFields.toArray(EMPTY_FIELD_ARRAY);
    }

}