java 对象比较 返回不相同的值
阅读原文时间:2023年07月08日阅读:2

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.soooft.common.equator;

import java.util.List;

public interface Equator {
/**
* 比较两个对象是否相同
*
* @param var1
* @param var2
* @return
*/
boolean isEquals(Object var1, Object var2);

/\*\*  
 \* 对象比较 支持对象嵌套比较 返回不同值  
 \*  
 \* @param var1  
 \* @param var2  
 \* @return  
 \*/  
List<FieldInfo> getDiffFields(Object var1, Object var2);  

}

1 package com.soooft.common.equator;
2
3 import java.util.*;
4 import java.util.stream.Collectors;
5 import java.util.stream.Stream;
6 /**
7 * @author xiazhiyong
8 * @description: TODO
9 * @date 2022/11/17
10 */
11 public abstract class AbstractEquator implements Equator {
12 private List includeFields;
13 private List excludeFields;
14 private boolean bothExistFieldOnly = true;
15
16 public AbstractEquator() {
17 this.includeFields = Collections.emptyList();
18 this.excludeFields = Collections.emptyList();
19 }
20
21 public AbstractEquator(boolean bothExistFieldOnly) {
22 this.includeFields = Collections.emptyList();
23 this.excludeFields = Collections.emptyList();
24 this.bothExistFieldOnly = bothExistFieldOnly;
25 }
26
27 public AbstractEquator(List includeFields, List excludeFields) {
28 this.includeFields = includeFields;
29 this.excludeFields = excludeFields;
30 }
31
32 public AbstractEquator(List includeFields, List excludeFields, boolean bothExistFieldOnly) {
33 this.includeFields = includeFields;
34 this.excludeFields = excludeFields;
35 this.bothExistFieldOnly = bothExistFieldOnly;
36 }
37
38 public boolean isEquals(Object first, Object second) {
39 List diff = this.getDiffFields(first, second);
40 return diff == null || diff.isEmpty();
41 }
42
43 protected boolean isFieldEquals(FieldInfo fieldInfo) {
44 if (this.isExclude(fieldInfo)) {
45 return true;
46 } else {
47 return !this.isInclude(fieldInfo) || this.nullableEquals(fieldInfo.getFirstVal(), fieldInfo.getSecondVal());
48 }
49 }
50
51 protected boolean isInclude(FieldInfo fieldInfo) {
52 return this.includeFields == null || this.includeFields.isEmpty() || this.includeFields.contains(fieldInfo.getFieldName());
53 }
54
55 protected boolean isExclude(FieldInfo fieldInfo) {
56 return this.excludeFields != null && !this.excludeFields.isEmpty() && this.excludeFields.contains(fieldInfo.getFieldName());
57 }
58
59 List compareSimpleField(Object first, Object second) {
60 boolean eq = Objects.equals(first, second);
61 if (eq) {
62 return Collections.emptyList();
63 } else {
64 Object obj = first == null ? second : first;
65 Class clazz = obj.getClass();
66 return Collections.singletonList(new FieldInfo(clazz.getSimpleName(), clazz, first, second, clazz.getName()));
67 }
68 }
69 Set getAllFieldNames(Set firstFields, Set secondFields) {
70 Object allFields;
71 if (this.isBothExistFieldOnly()) {
72 Stream var10000 = firstFields.stream();
73 secondFields.getClass();
74 allFields = var10000.filter(secondFields::contains).collect(Collectors.toSet());
75 } else {
76 allFields = new HashSet(firstFields);
77 ((Set) allFields).addAll(secondFields);
78 }
79
80 return (Set) allFields;
81 }
82
83 private boolean nullableEquals(Object first, Object second) {
84 return first instanceof Collection && second instanceof Collection ? Objects.deepEquals(((Collection) first).toArray(), ((Collection) second).toArray()) : Objects.deepEquals(first, second);
85 }
86
87 public void setIncludeFields(List includeFields) {
88 this.includeFields = includeFields;
89 }
90
91 public void setExcludeFields(List excludeFields) {
92 this.excludeFields = excludeFields;
93 }
94
95 public void setBothExistFieldOnly(boolean bothExistFieldOnly) {
96 this.bothExistFieldOnly = bothExistFieldOnly;
97 }
98
99 public List getIncludeFields() {
100 return this.includeFields;
101 }
102
103 public List getExcludeFields() {
104 return this.excludeFields;
105 }
106
107 public boolean isBothExistFieldOnly() {
108 return this.bothExistFieldOnly;
109 }
110 }

1 package com.soooft.common.equator;
2
3 import cn.hutool.core.util.ClassUtil;
4 import cn.hutool.core.util.StrUtil;
5 import lombok.extern.log4j.Log4j;
6
7 import java.lang.reflect.Field;
8 import java.util.*;
9
10 /**
11 * @author xiazhiyong
12 * @description: TODO
13 * @date 2022/11/17
14 */
15 @Log4j
16 public class MyFieldBaseEquator extends AbstractEquator {
17 public MyFieldBaseEquator() {
18 }
19
20 /**
21 * 指定包含或排除某些字段
22 *
23 * @param includeFields 包含字段,若为 null 或空集,则不指定
24 * @param excludeFields 排除字段,若为 null 或空集,则不指定
25 */
26 public MyFieldBaseEquator(List includeFields, List excludeFields) {
27 super(includeFields, excludeFields);
28 }
29
30 /**
31 * {@inheritDoc}
32 */
33 @Override
34 public List getDiffFields(Object first, Object second) {
35 if (first == second) {
36 return Collections.emptyList();
37 }
38 // 先尝试判断是否为简单数据类型
39 if (isSimpleField(first, second)) {
40 return compareSimpleField(first, second);
41 }
42 Object obj = first == null ? second : first;
43
44 String className = obj.getClass().getName();
45 Class clazz = obj.getClass();
46 List diffField = new LinkedList<>();
47 // 获取所有字段
48 Field[] fields = clazz.getDeclaredFields();
49 // 遍历所有的字段
50 for (Field firstField : fields) {
51
52 String fieldName = firstField.getName();
53
54 try {
55 Field secondField = second.getClass().getDeclaredField(fieldName);
56 firstField.setAccessible(true);
57 secondField.setAccessible(true);
58 // 开启访问权限,否则获取私有字段会报错
59 Object firstVal = first == null ? null : firstField.get(first);
60 Object secondVal = secondField.get(second);
61 if (ClassUtil.isBasicType(firstField.getType()) || (firstVal instanceof Collection && secondVal instanceof Collection)) {
62 // 封装字段信息
63 FieldInfo fieldInfo = new FieldInfo(fieldName, firstField.getType(), firstVal, secondVal, className);
64 boolean eq = isFieldEquals(fieldInfo);
65 if (!eq) {
66 // 记录不相等的字段
67 diffField.add(fieldInfo);
68 }
69 } else if (onlyOneNull(firstVal, secondVal)) {
70 FieldInfo fieldInfo = new FieldInfo(fieldName, firstField.getType(), firstVal, secondVal, className);
71 diffField.add(fieldInfo);
72 } else if (Objects.isNull(firstVal) && Objects.isNull(secondVal)) {
73 log.debug("双方都为null,不做记录");
74 } else {
75 if (StrUtil.equals(className, Date.class.getName())) {
76 continue;
77 }
78 diffField.addAll(getDiffFields(firstVal, secondVal));
79 }
80 } catch (IllegalAccessException e) {
81 // 只要调用了 firstField.setAccessible(true) 就不会报这个异常
82 throw new IllegalStateException("获取属性进行比对发生异常: " + fieldName, e);
83 } catch (NoSuchFieldException ignored) {
84
85 }
86 }
87 return diffField;
88 }
89
90 private boolean onlyOneNull(Object firstVal, Object secondVal) {
91 return (Objects.isNull(firstVal) && Objects.nonNull(secondVal)) || (Objects.isNull(secondVal) && Objects.nonNull(firstVal));
92 }
93
94
95 /**
96 * 如果简单数据类型的对象则直接进行比对
97 *
98 * @param first 对象1
99 * @param second 对象2
100 * @return 不同的字段信息,相等返回空集,不等则 FieldInfo 的字段名为对象的类型名称
101 */
102 List compareSimpleField(Object first, Object second) {
103 boolean eq = Objects.equals(first, second);
104 if (eq) {
105 return Collections.emptyList();
106 } else {
107 Object obj = first == null ? second : first;
108 Class clazz = obj.getClass();
109 // 不等的字段名称使用类的名称
110 return Collections.singletonList(new FieldInfo(clazz.getSimpleName(), clazz, first, second, clazz.getName()));
111 }
112 }
113
114 /**
115 * 判断是否为原始数据类型
116 *
117 * @param first 对象1
118 * @param second 对象2
119 * @return 是否为原始数据类型
120 */
121 boolean isSimpleField(Object first, Object second) {
122 Object obj = first == null ? second : first;
123 Class clazz = obj.getClass();
124 return clazz.isPrimitive() || ClassUtil.isBasicType(clazz);
125 }
126 }