Gods_巨蚁

我通过代码实现了一款软件,同时也通过优雅的代码向其中注入灵魂 QQ:517377100 E-mail:ljsunlin@126.com 网站作品小蚂蚁工具箱anttoolbox.cn

导航

[原创]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 == null && updatedValue == null)
                        continue;

                    if (originalValue == 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
 
若有必要,则可以稍加重构转换为泛型方法,支持何种数据类型的差异性检测

posted on 2015-01-04 20:06  Gods_巨蚁  阅读(738)  评论(0编辑  收藏  举报

anttoolbox.cn