1. Preface
At work, we may record data changes in the log or add a log page to the publicly processed data to record changes in each modification. We can compare the changes before and after the data according to the CompareUtils tool class, so that we can know what changes the data has made.
2. Conditional restrictions
When writing this general method, we should consider the following points:
(1) You can receive comparisons of any object, but the comparison object should be the same object;
(2) You can make a note to the field, because the final content we see should be a Chinese name;
(3) In an object, you can get some fields for comparison, and those without annotations do not need to compare;
(4) In an object, other fields can be used for comparison and output certain fields, such as annotating the field userName, using userId (user ID) to compare, and output userName (user name);
(5) In an object, fields can be formatted and output, such as amount, date and time, etc.
3. Code
CompareAnon (Compare Interface) (Custom Annotation)
import ; import ; import ; import ; /** * Comparative Notes */ @Target(value = {, }) // Allow modified annotations to be used on classes, interfaces and enums // Allow to be used on attribute fields@Retention() // Annotations are retained at runtime and can be obtained through reflectionpublic @interface CompareAnon { /** * Field Chinese name */ String name(); /** * Prefix field (split, i.e.: prefixField field value + name) */ String prefixField() default ""; /** * Compare fields (without the original field for comparison) */ String compareField() default ""; /** * When adding or deleting, whether to use this value as the "field value" * like: * Added -> Field value * Field value -> Delete */ boolean asContent() default false; /** * Format */ String pattern() default ""; }
ComparedResult
import ; /** * Comparison results */ public class ComparedResult implements Serializable { /** * Comparison fields */ private String field; /** * Comparison field name (description) */ private String fieldName; /** * Original value */ private Object oldValue; /** * Modified value */ private Object newValue; /** * Original value (string) */ private String oldContent; /** * Modified value (string) */ private String newContent; /** * Format */ private String pattern; /** * Remark */ private String remark; public String getField() { return field; } public void setField(String field) { = field; } public String getFieldName() { return fieldName; } public void setFieldName(String fieldName) { = fieldName; } public Object getOldValue() { return oldValue; } public void setOldValue(Object oldValue) { = oldValue; } public Object getNewValue() { return newValue; } public void setNewValue(Object newValue) { = newValue; } public String getOldContent() { return oldContent; } public void setOldContent(String oldContent) { = oldContent; } public String getNewContent() { return newContent; } public void setNewContent(String newContent) { = newContent; } public String getPattern() { return pattern; } public void setPattern(String pattern) { = pattern; } public String getRemark() { return remark; } public void setRemark(String remark) { = remark; } @Override public String toString() { return "ComparedResult{" + "field='" + field + '\'' + ", fieldName='" + fieldName + '\'' + ", oldValue=" + oldValue + ", newValue=" + newValue + ", oldContent='" + oldContent + '\'' + ", newContent='" + newContent + '\'' + ", pattern='" + pattern + '\'' + ", remark='" + remark + '\'' + '}'; } }
Order DTO (test class)
import ; import ; import ; /** * Order DTO */ @CompareAnon(name = "Order") public class OrderDTO implements Serializable { @CompareAnon(name = "Order id") private String id; @CompareAnon(name = "Order number", asContent = true) private String orderCode; private String supplyId; @CompareAnon(name = "Supplier Name", compareField = "supplyId") private String supplyName; @CompareAnon(name = "Order Amount (yuan)", pattern = "#,##0.0000") private BigDecimal orderAmount; @CompareAnon(name = "Order Date", pattern = "yyyy-MM-dd HH:mm:ss") private Date orderDate; public String getId() { return id; } public void setId(String id) { = id; } public String getOrderCode() { return orderCode; } public void setOrderCode(String orderCode) { = orderCode; } public String getSupplyId() { return supplyId; } public void setSupplyId(String supplyId) { = supplyId; } public String getSupplyName() { return supplyName; } public void setSupplyName(String supplyName) { = supplyName; } public BigDecimal getOrderAmount() { return orderAmount; } public void setOrderAmount(BigDecimal orderAmount) { = orderAmount; } public Date getOrderDate() { return orderDate; } public void setOrderDate(Date orderDate) { = orderDate; } }
CompareUtils (Compare Tool Class)
import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; /** * Comparison tool class */ public class CompareUtils { /** * Compare different values, whether they are equal * * @param o1 value 1 * @param o2 value 2 * @return Comparison results, true is equal, false is not equal */ public static boolean compareValues(Object o1, Object o2) { if (o1 == null && o2 == null) { return true; } if (o1 != null && o2 == null) { return false; } if (o1 == null && o2 != null) { return false; } // BigDecimal uses compareTo if (o1 instanceof BigDecimal && o2 instanceof BigDecimal) { BigDecimal decimal1 = new BigDecimal((o1)); BigDecimal decimal2 = new BigDecimal((o2)); // 0 equal return (decimal2) == 0; } if (o1 instanceof Timestamp) { o1 = new Date(((Timestamp) o1).getTime()); } if (o2 instanceof Timestamp) { o2 = new Date(((Timestamp) o2).getTime()); } return (o1, o2); } /** * Compare the two objects to modify the value * @param oldObject OldObject * @param newObject * @return Comparison result list */ public static List<ComparedResult> compareTwoObject(Object oldObject, Object newObject) { // When null, no comparison if (null == oldObject || null == newObject) { return (); } // Not the same class if (() != ()) { throw new RuntimeException("Not the same class!"); } List<ComparedResult> comparedResultList = new ArrayList<>(); Class<?> clazz = (); // Get all fields Field[] Fields = (); for (Field field : Fields) { try { // Get annotation CompareAnon compareAnon = (); // No annotation means no comparison fields, skip if (null == compareAnon) { continue; } String fieldKey = (); // Field name String filedName = (); // Field Chinese name String pattern = (); // Format // Prefix field exists (sticking, that is: prefixField field value + name) String prefixField = (); if ((prefixField)) { filedName = getFieldValue(prefixField, oldObject) + filedName; } // Compare field names String compareField = (); if ((())) { compareField = (); } // Get the value of the comparison attribute // Calling the get method on oldObject is equivalent to getting the property value of oldObject Object oldCompareValue = getFieldValue(compareField, oldObject); // Calling the get method on newObject is equivalent to getting the property value of newObject Object newCompareValue = getFieldValue(compareField, newObject); // Calling the get method on oldObject is equivalent to getting the property value of oldObject Object oldValue = getFieldValue(fieldKey, oldObject); // Calling the get method on newObject is equivalent to getting the property value of newObject Object newValue = getFieldValue(fieldKey, newObject); // Original value (string) String oldContent = (oldValue, pattern); // Modified value (string) String newContent = (newValue, pattern); // Compare whether the two values are consistent if (!compareValues(oldCompareValue, newCompareValue)) { // Inconsistent ComparedResult result = new ComparedResult(); (fieldKey); (filedName); (oldValue); (newValue); (oldContent); (newContent); (pattern); (oldContent + " -> " + newContent); (result); } } catch (Exception e) { (); } } return comparedResultList; } /** * Compare the two objects to modify the value (check whether it is null) * @param oldObject OldObject * @param newObject * @return Comparison result list */ public static List<ComparedResult> compareTwoObjectCheckNull(Object oldObject, Object newObject) { // When all are null, no comparison if (null == oldObject && null == newObject) { return (); } // Added if (null == oldObject && null != newObject) { // Return to new comparison results return addComparedResult(newObject); } // delete if (null != oldObject && null == newObject) { // Return to delete comparison results return deleteComparedResult(oldObject); } // When neither is null, compare the two objects to modify the value return compareTwoObject(oldObject, newObject); } /** * Added comparison results * @param obj object * @return Comparison results */ public static List<ComparedResult> addComparedResult(Object obj) { List<ComparedResult> comparedResultList = new ArrayList<>(); Class<?> clazz = (); String filedName = ""; // Field Chinese name String content = ""; // content // Get class annotations CompareAnon anon = (); if (null != anon) { filedName = (); } // Get all fields Field[] Fields = (); for (Field field : Fields) { try { // Get annotation CompareAnon compareAnon = (); // No annotation means no comparison fields, skip if (null == compareAnon) { continue; } String fieldKey = (); // Field name boolean asContent = (); // Whether to use this value as a "field value" if (asContent) { Object value = getFieldValue(fieldKey, obj); // Field value content = (value, null); } } catch (Exception e) { (); } } // Add new results ComparedResult result = new ComparedResult(); (filedName); ("New"); (content); ("New"); (result); return comparedResultList; } /** * Delete the comparison results * @param obj object * @return Comparison results */ public static List<ComparedResult> deleteComparedResult(Object obj) { List<ComparedResult> comparedResultList = new ArrayList<>(); Class<?> clazz = (); String filedName = ""; // Field Chinese name String content = ""; // content // Get class annotation CompareAnon anon = (); if (null != anon) { filedName = (); } // Get all fields Field[] Fields = (); for (Field field : Fields) { try { // Get annotation CompareAnon compareAnon = (); // No annotation means no comparison fields, skip if (null == compareAnon) { continue; } String fieldKey = (); // Field name boolean asContent = (); // Whether to use this value as a "field value" if (asContent) { Object value = getFieldValue(fieldKey, obj); // Field value content = (value, null); } } catch (Exception e) { (); } } // Delete the result ComparedResult result = new ComparedResult(); (filedName); (content); ("delete"); ("delete"); (result); return comparedResultList; } /** * Get field value * @param fieldKey field name * @param obj object * @return field value * @throws Exception */ public static Object getFieldValue(String fieldKey, Object obj) throws Exception { PropertyDescriptor pd = new PropertyDescriptor(fieldKey, ()); Method getMethod = (); // Calling the get method on obj is equivalent to getting the attribute value of obj return (obj); } public static void main(String[] args) { (compareValues(null, null)); (compareValues(2, null)); (compareValues(null, 2)); (compareValues(2, 2)); (compareValues("2", "2")); (compareValues(2, "2")); ("------------------------BigDecimal---------------------------"); (compareValues(new BigDecimal("2"), "2")); (compareValues(new BigDecimal("2"), new BigDecimal("2.0000"))); (compareValues(new BigDecimal("2.00"), new BigDecimal("2.0000"))); (compareValues(new BigDecimal("2.0000"), new BigDecimal("2.0000"))); (compareValues(new BigDecimal("2.0000"), new BigDecimal("3.0000"))); ("------------------------comparedResultList---------------------------"); OrderDTO oldDTO = new OrderDTO(); ("1"); ("Order 1"); ("1"); ("Supplier Name 1"); (new BigDecimal("111111")); (new Date()); OrderDTO newDTO = new OrderDTO(); ("2"); ("Order 2"); ("2"); ("Supplier Name 2"); (new BigDecimal("222222")); ((new Date())); List<ComparedResult> comparedResultList = compareTwoObject(oldDTO, newDTO); for (ComparedResult comparedResult : comparedResultList) { (()); } ("------------------------comparedResultList2---------------------------"); OrderDTO orderDTO = new OrderDTO(); ("3"); ("Order 3"); ("3"); ("Supplier Name 3"); (new BigDecimal("333333")); ((new Date())); List<ComparedResult> comparedResultList2 = compareTwoObjectCheckNull(null, orderDTO); for (ComparedResult comparedResult : comparedResultList2) { (()); } ("------------------------comparedResultList3---------------------------"); List<ComparedResult> comparedResultList3 = compareTwoObjectCheckNull(orderDTO, null); for (ComparedResult comparedResult : comparedResultList3) { (()); } } }
4. Main method, output result
true
false
false
true
true
false
------------------------BigDecimal---------------------------
false
true
true
true
false
------------------------comparedResultList---------------------------
ComparedResult{field='id', fieldName='Order id', oldValue=1, newValue=2, oldContent='1', newContent='2', pattern='', remark='1 -> 2'}
ComparedResult{field='orderCode', fieldName='Order number', oldValue=Order1, newValue=Order2, oldContent='Order1', newContent='Order2', pattern='', remark='Order1 ->Order2'}
ComparedResult{field='supplyName', fieldName='SupplyName', oldValue=SupplyName1, newValue=SupplyName2, oldContent='SupplyName1', newContent='SupplyName2', pattern='', remark='SupplyName1->SupplyName2'}
ComparedResult{field='orderAmount', fieldName='Order Amount (yuan)', oldValue=111111, newValue=222222, oldContent='111,111.0000', newContent='222,222.0000', pattern='#,##0.0000', remark='111,111.0000 -> 222,222.0000'}
ComparedResult{field='orderDate', fieldName='Order Date', oldValue=Wed Mar 20 11:51:22 CST 2024, newValue=Thu Mar 21 11:51:22 CST 2024, oldContent='2024-03-20 11:51:22', newContent='2024-03-21 11:51:22', pattern='yyyy-MM-dd HH:mm:ss', remark='2024-03-20 11:51:22 -> 2024-03-21 11:51:22'}
------------------------comparedResultList2---------------------------
ComparedResult{field='null', fieldName='Order', oldValue=null, newValue=null, oldContent='Add', newContent='Order3', pattern='null', remark='Add'}
------------------------comparedResultList3---------------------------
ComparedResult{field='null', fieldName='Order', oldValue=null, newValue=null, oldContent='Order3', newContent='Delete', pattern='null', remark='Delete'}
The above is a detailed explanation of the example of Java comparing the changes of two entity class fields. For more information about Java comparing the changes of entity class fields, please pay attention to my other related articles!