首页 > 代码库 > [原创]Java使用反射及自定义注解实现对象差异性比较

[原创]Java使用反射及自定义注解实现对象差异性比较

Java项目C中 有一处逻辑,对于资源数据(类型为ResourceItem,拥有int/double/boolean/String类型数十个字段),需要比对资源数据每次变更的差异,并描述出变更情况。并非所有的字段都需要比对,如id字段则不参与比对。
 
依次比对每一个字段编写代码比对,将是个重苦力活。高级语言给予了我们诸多便利,应当加以利用。
 
首先定义自己的注解,value值用作字段描述
@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interface RevisionColumn {    String value();}
 
为ResourceItem所有待比对字段添加该注解,如
public class ResourceItem {    private int id;    private int revision;    private ResourceItemStatus status;     @RevisionColumn("节点")    private String node;     @RevisionColumn("是否物理隔离")    private boolean physicalIsolation;     @RevisionColumn("整机:单盘上限(%)")    private int machineDiskLimit;       //...}
 
介绍比对逻辑前,首先定义记录对象字段差异的实体类型
技术分享
public class FieldChangeInfo implements Serializable{    private String propertyName;    private String propertyHeader;    private Object from;    private Object to;     public FieldChangeInfo() {    }     public FieldChangeInfo(String propertyName, String propertyHeader, Object from, Object to) {        this.propertyName = propertyName;        this.propertyHeader = propertyHeader;        this.from = from;        this.to = to;    }     @Override    public boolean equals(Object obj) {        if (!(obj instanceof FieldChangeInfo))            return false;        if (obj == this)            return true;         FieldChangeInfo rhs = (FieldChangeInfo) obj;        return new EqualsBuilder().                append(propertyName, rhs.propertyName).                append(propertyHeader, rhs.propertyHeader).                append(from, rhs.from).                append(to, rhs.to).                isEquals();    }     public String getPropertyName() {        return propertyName;    }     public void setPropertyName(String propertyName) {        this.propertyName = propertyName;    }     public String getPropertyHeader() {        return propertyHeader;    }     public void setPropertyHeader(String propertyHeader) {        this.propertyHeader = propertyHeader;    }     public Object getFrom() {        return from;    }     public void setFrom(Object from) {        this.from = from;    }     public Object getTo() {        return to;    }     public void setTo(Object to) {        this.to = to;    }}
FieldChangeInfo
 
Resource数据比对逻辑,实现如下工具方法
1、参数接受ResourceItem新旧两个对象
2、通过反射,class.getDeclaredFields获取类型的所有字段
3、调用Field实例的getAnnotation方法,获取RevisionColumn注解对象,若不为null,则说明该字段设置了该注解,进行比对
4、获取字段值,检测空引用,调用equals方法做值比对,出现不匹配,则创建FiledChangeInfo对象记录差异信息
5、返回差异信息集合
 
技术分享
    public static List<FieldChangeInfo> getResourceItemFieldChangeInfo(ResourceItem originalItem, ResourceItem updatedItem) {        try {            List<FieldChangeInfo> fieldChangeInfos = new LinkedList<>();            for (Field field : ResourceItem.class.getDeclaredFields()) {                RevisionColumn revisionColumn = field.getAnnotation(RevisionColumn.class);                if (revisionColumn != null)                {                    field.setAccessible(true);                    Object originalValue = field.get(originalItem);                    Object updatedValue = field.get(updatedItem);                    if (originalValue =http://www.mamicode.com/= null && updatedValue =http://www.mamicode.com/= null)                        continue;                    if (originalValue =http://www.mamicode.com/= null || !originalValue.equals(updatedValue)){                        FieldChangeInfo fieldChangeInfo = new FieldChangeInfo();                        fieldChangeInfo.setFrom(originalValue);                        fieldChangeInfo.setTo(updatedValue);                        fieldChangeInfo.setPropertyName(field.getName());                        fieldChangeInfo.setPropertyHeader(revisionColumn.value());                        fieldChangeInfos.add(fieldChangeInfo);                    }                }            }            return fieldChangeInfos;        } catch (IllegalAccessException e) {            throw new RuntimeException("检测ResourceItem字段变更时出现异常");        }    }
getResourceItemFieldChangeInfo
 
若有必要,则可以稍加重构转换为泛型方法,支持何种数据类型的差异性检测

[原创]Java使用反射及自定义注解实现对象差异性比较