Compare two object field values and return field names with inconsistent values

need:

Compare the details of the two versions, and mark the place where the modification occurs to indicate that there is a modification here.

PART 1:

Improved from the copyProperties method under org.springframework.beans.BeanUtils

	/**
     * 比较两个对象的不同字段
     * @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:

After the end of the previous edition, I took the front-end to develop the interface, and then the front-end students proposed that the values ​​of the sub-objects under the object were inconsistent and could not be recognized. After thinking about it, let’s recurse. The recursive condition is that if there are multiple field values ​​in the current field, it will go deeper. If there is only one field value, why should it be placed in the object!
There must be more recursive pits, so the verification of some fields is excluded, otherwise there will be infinite dolls.

/**
 * 校验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;
    }
}

Part 3:

Front end: Your string in JSON format is not refined to each line, I can’t do it,,,, it’s impossible, big brother, put down the knife and talk,,, ah,,

Ah, the world is quiet

Guess you like

Origin blog.csdn.net/qq_16253859/article/details/123982645