Java 记录类中所有字段改变前,改变后的数据
需求:记录类中所有字段的改动,包含改动字段、改动字段路径、改动前数据值、改动后数据值、包含类中List和枚举的改动。
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
public class ModifyFieldUtil {
public static List record(Class> clazz, Object oldObj, Object newObj, String columnPath) throws Exception {
if (oldObj == newObj) {
return new ArrayList<>();
}
Field[] fields = clazz.getDeclaredFields();
List allFields = new ArrayList<>();
String tableName = "";
String resourceId = "";
for (Field field : fields) {
field.setAccessible(true);
if (field.isAnnotationPresent(HistoryResourceId.class)) {
resourceId = String.valueOf(field.get(oldObj));
}
if (field.isAnnotationPresent(HistoryTableName.class)) {
tableName = field.getAnnotation(HistoryTableName.class).tableName();
}
//removing fields that do not need to be recorded
if (!field.isAnnotationPresent(JsonIgnore.class)) {
allFields.add(field);
}
}
List list = new ArrayList<>();
return getFieldList(list, allFields, tableName, resourceId, columnPath, oldObj, newObj, false);
}
public static List getFieldList(List recordList, List fields, String tableName, String resourceId, String columnPath, Object oldObj, Object newObj, Boolean isListObj) throws Exception {
List arrayList = new ArrayList<>();
int j = 0;
for (Field field : fields) {
field.setAccessible(true);
String key = field.getName();
if (StringUtils.isNotBlank(columnPath)) {
key = StringUtils.join(columnPath, ".", key);
}
//check the field type
Boolean fliedTypeIsListOrCustomClassCheckResult = checkFliedTypeIsListOrCustomClass(field, oldObj);
if (fliedTypeIsListOrCustomClassCheckResult) {
//the type is a list
if (isList(field, oldObj)) {
if (field.get(oldObj) == field.get(newObj)) {
continue;
}
Class listClazz = field.get(oldObj).getClass();
//get size method
Method getSizeMethod = listClazz.getDeclaredMethod("size");
//get old/new list size
int oldListSize = field.get(oldObj) == null ? 0 : (Integer) getSizeMethod.invoke(field.get(oldObj));
int newListSize = field.get(newObj) == null ? 0 : (Integer) getSizeMethod.invoke(field.get(newObj));
if (oldListSize != newListSize) {
//if new list size is equals old list size,save the list
recordList.add(new Record(field.getName(), JsonUtil.getPrettyJSON(field.get(oldObj)),
JsonUtil.getPrettyJSON(field.get(newObj)),
tableName, key, resourceId));
continue;
}
for (int i = 0; i < oldListSize; i++) {
Method getObjMethod = listClazz.getDeclaredMethod("get", int.class);
getObjMethod.setAccessible(true);
Object oldListObj = field.get(oldObj) == null ? null : getObjMethod.invoke(field.get(oldObj), i);
Object newListObj = field.get(newObj) == null ? null : getObjMethod.invoke(field.get(newObj), i);
//define columnPath value
String listKey = !StringUtils.isEmpty(key) ? StringUtils.join(key, "[", i, "]") : "";
getFieldList(recordList, Arrays.asList(oldListObj.getClass().getDeclaredFields()), tableName, resourceId, listKey, oldListObj, newListObj, true);
}
} else {
//the field type is not list
getFieldList(recordList, Arrays.asList(field.get(newObj).getClass().getDeclaredFields()), tableName, resourceId, key, field.get(oldObj), field.get(newObj), true);
}
} else {
if (isNull(field, oldObj) && isNull(field, newObj)) {
continue;
}
//if the field type is not custom class and list save the recorded
j++;
String modifyFrom = oldObj == null || field.get(oldObj) == null ? "" : getStringValue(field.get(oldObj));
String modifyTo = newObj == null || field.get(newObj) == null ? "" : getStringValue(field.get(newObj));
if (StringUtils.isBlank(modifyFrom)) {
continue;
}
if (!modifyFrom.equals(modifyTo)) {
if (isListObj) {
arrayList.add(new Record(field.getName(), modifyFrom, modifyTo,
tableName, key, resourceId));
} else {
recordList.add(new Record(field.getName(), modifyFrom, modifyTo,
tableName, key, resourceId));
}
}
}
}
//if all the fields changed in the class, save his father's class path
if (arrayList.size() == j) {
recordList.add(new Record(columnPath, JsonUtil.getPrettyJSON(oldObj),
JsonUtil.getPrettyJSON(newObj),
tableName, columnPath, resourceId));
} else {
recordList.addAll(arrayList);
}
arrayList = new ArrayList<>();
return recordList;
}
public static String getStringValue(Object obj) {
return null == obj ? "" : JsonUtil.getPrettyJSON(obj);
}
public static Boolean checkFliedTypeIsListOrCustomClass(Field field, Object javaBean) throws IllegalAccessException {
if (getFieldValue(field, javaBean) instanceof Enum>) {
return false;
}
return isCustomClass(field, javaBean) || isList(field, javaBean);
}
public static Boolean isList(Field field, Object javaBean) throws IllegalAccessException {
Object fieldValue = getFieldValue(field, javaBean);
return null != fieldValue && fieldValue instanceof Collection> && fieldValue instanceof Enum>;
}
public static Boolean isCustomClass(Field field, Object javaBean) throws IllegalAccessException {
Object fieldValue = getFieldValue(field, javaBean);
return null != fieldValue && null != fieldValue.getClass().getClassLoader();
}
public static Object getFieldValue(Field field, Object javaBean) throws IllegalAccessException {
return null == javaBean ? null : field.get(javaBean);
}
private static Boolean isNull(Field field, Object javaBean) throws IllegalAccessException {
return null == getFieldValue(field, javaBean);
}
public class Record {
private String column;
private String modifyFrom;
private String modifyTo;
private String tableName;
private String columnPath;
private String resourceId;
public Record() {
}
public Record(String column, String modifyFrom, String modifyTo, String tableName, String columnPath, String resourceId) {
this.column = column;
this.modifyFrom = modifyFrom;
this.modifyTo = modifyTo;
this.tableName = tableName;
this.columnPath = columnPath;
this.resourceId = resourceId;
}
public String getColumn() {
return column;
}
public void setColumn(String column) {
this.column = column;
}
public String getModifyFrom() {
return modifyFrom;
}
public void setModifyFrom(String modifyFrom) {
this.modifyFrom = modifyFrom;
}
public String getModifyTo() {
return modifyTo;
}
public void setModifyTo(String modifyTo) {
this.modifyTo = modifyTo;
}
public String getTableName() {
return tableName;
}
public void setTableName(String tableName) {
this.tableName = tableName;
}
public String getColumnPath() {
return columnPath;
}
public void setColumnPath(String columnPath) {
this.columnPath = columnPath;
}
public String getResourceId() {
return resourceId;
}
public void setResourceId(String resourceId) {
this.resourceId = resourceId;
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target({java.lang.annotation.ElementType.FIELD})
public @interface HistoryResourceId {
}
@Retention(RetentionPolicy.RUNTIME)
@Target({java.lang.annotation.ElementType.FIELD})
public @interface HistoryTableName {
String tableName();
}