java - 比对两个对象字段值,并且返回值不一致的字段名称

需求:

对比两个版本的详情,对出现修改的地方进行标注表示此处有修改。

PART 1:

改良自org.springframework.beans.BeanUtils下的copyProperties方法

	/**
     * 比较两个对象的不同字段
     * @return
     */
    public static List<String> checkDiffFiled(Object source, Object target){
    
    

        List<String> result = new ArrayList<>();

        Assert.notNull(source, "Source must not be null");
        Assert.notNull(target, "Target must not be null");

        Class<?> actualEditable = target.getClass();
        PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);

        for (PropertyDescriptor targetPd : targetPds) {
    
    
            PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());
            if (sourcePd != null) {
    
    
                //获取两个目标字段的read方法
                Method readTarget = targetPd.getReadMethod();
                Method readSource = sourcePd.getReadMethod();
                if (readTarget != null && readSource != null) {
    
    
                    ResolvableType sourceResolvableType = ResolvableType.forMethodReturnType(readSource);
                    ResolvableType targetResolvableType = ResolvableType.forMethodReturnType(readTarget);

                    // Ignore generic types in assignable check if either ResolvableType has unresolvable generics.
                    //比较两个字段类型值是否一致
                    boolean isAssignable =
                            (sourceResolvableType.hasUnresolvableGenerics() || targetResolvableType.hasUnresolvableGenerics() ?
                                    ClassUtils.isAssignable(readTarget.getReturnType(), readSource.getReturnType()) : targetResolvableType.isAssignableFrom(sourceResolvableType));

                    if (isAssignable) {
    
    
                        try {
    
    
                            if (!Modifier.isPublic(readSource.getDeclaringClass().getModifiers())) {
    
    
                                readSource.setAccessible(true);
                            }
                            Object value1 = readSource.invoke(source);
                            if (!Modifier.isPublic(readTarget.getDeclaringClass().getModifiers())) {
    
    
                                readTarget.setAccessible(true);
                            }
                            Object value2 = readTarget.invoke(target);
                            if (!Objects.equals(value1,value2))
                                result.add(targetPd.getName());
                        }
                        catch (Throwable ex) {
    
    
                            throw new FatalBeanException(
                                    "Could not copy property '" + targetPd.getName() + "' from source to target", ex);
                        }
                    }
                }
            }
        }

        return result;
    }

PART 2:

在上一版结束后,拿去前端对接口开发了,随后前端同学提出对象下的子对象的值不一致无法识别到。思考了一下咱递归不就行了,递归条件是如果当前字段存在多个字段值就往下深入,如果只有一个字段值为啥要放在对象里呢!
递归的坑点肯定比较多,所以排除了一些字段的校验,否则会无限套娃。

/**
 * 校验Bean工具类
 */
public class CheckBeanUtil {
    
    

    /**
     * 比较两个对象的不同字段
     * @param source
     * @param target
     * @param pPath
     * @return
     */
    public static List<String> checkDiffFiled(Object source, Object target, @Nullable String pPath){
    
    

        List<String> result = new ArrayList<>();

        if (!StringUtils.hasText(pPath))
            pPath = "";

        Assert.notNull(source, "Source must not be null");
        Assert.notNull(target, "Target must not be null");

        Class<?> actualEditable = target.getClass();
        PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);

        for (PropertyDescriptor targetPd : targetPds) {
    
    
            if (targetPd.getName().equals("class"))
                continue;
            PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());
            if (sourcePd != null) {
    
    
                //获取两个目标字段的read方法
                Method readTarget = targetPd.getReadMethod();
                Method readSource = sourcePd.getReadMethod();
                if (readTarget != null && readSource != null) {
    
    
                    ResolvableType sourceResolvableType = ResolvableType.forMethodReturnType(readSource);
                    ResolvableType targetResolvableType = ResolvableType.forMethodReturnType(readTarget);

                    // Ignore generic types in assignable check if either ResolvableType has unresolvable generics.
                    //比较两个字段类型值是否一致
                    boolean isAssignable =
                            (sourceResolvableType.hasUnresolvableGenerics() || targetResolvableType.hasUnresolvableGenerics() ?
                                    ClassUtils.isAssignable(readTarget.getReturnType(), readSource.getReturnType()) : targetResolvableType.isAssignableFrom(sourceResolvableType));

                    if (isAssignable) {
    
    
                        try {
    
    
                            if (!Modifier.isPublic(readSource.getDeclaringClass().getModifiers())) {
    
    
                                readSource.setAccessible(true); //如果是私有化字段,开启允许访问
                            }
                            Object value1 = readSource.invoke(source);
                            if (!Modifier.isPublic(readTarget.getDeclaringClass().getModifiers())) {
    
    
                                readTarget.setAccessible(true); //如果是私有化字段,开启允许访问
                            }
                            Object value2 = readTarget.invoke(target);
                            if (Objects.nonNull(value1) && Objects.nonNull(value2) && checkType(value1) && getPropertyDescriptors(value1.getClass()).length > 1){
    
    
                                //如果存在多个字段,递归继续深入
                                result.addAll(checkDiffFiled(value1,value2,pPath + targetPd.getName() + "."));
                            }else if (!Objects.equals(value1,value2))
                                result.add(pPath + targetPd.getName());
                        }
                        catch (Throwable ex) {
    
    
                            throw new FatalBeanException(
                                    "Could not compaire property '" + targetPd.getName() + "' from source to target", ex);
                        }
                    }
                }
            }
        }

        return result;
    }

    //略过一些java对象
    private static boolean checkType(Object obj){
    
    
        if (obj instanceof String
                || obj instanceof LocalDateTime
                || obj instanceof JSONArray
            )
            return false;
        return true;
    }
}

Part3:

前端:你这JSON格式的字符串没有细化到每一行啊,我这干不了,,,,是不可能的,大哥你先放下刀好好说话,,,啊,,

啊,世界清静了

猜你喜欢

转载自blog.csdn.net/qq_16253859/article/details/123982645