需求:
对比两个版本的详情,对出现修改的地方进行标注表示此处有修改。
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格式的字符串没有细化到每一行啊,我这干不了,,,,是不可能的,大哥你先放下刀好好说话,,,啊,,
啊,世界清静了