zoukankan      html  css  js  c++  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 == 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
     
    若有必要,则可以稍加重构转换为泛型方法,支持何种数据类型的差异性检测
  • 相关阅读:
    数据库字段包含反斜杠的查询处理
    sql中的日期时间处理
    查询时间的测试
    group by 和 聚合函数的使用
    比较版本号
    sql IIF函数的应用
    win10系统杀毒功能
    php性能的问题
    linux 下ab压力测试
    datatables的学习总结
  • 原文地址:https://www.cnblogs.com/gods/p/4202023.html
Copyright © 2011-2022 走看看