[原创]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

若有必要,则可以稍加重构转换为泛型方法,支持何种数据类型的差异性检测

时间: 2024-10-25 11:19:20

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

Java反射与自定义注解

反射,在Java常用框架中屡见不鲜.它存在于java.lang.reflact包中,就我的认识,它可以拿到类的字段和方法,及构造方法,还可以生成对象实例等.对深入的机制我暂时还不了解,本篇文章着重在使用方面,并附上一个本人应用到项目中的案例. 基础姿势 拿到类,反射是以类为基础的基础,首先拿到项目中的类,既可以这样拿 Class<?> clazz = Class.forName(类路径); 也可以这样拿 Class<?> clazz = 类名.getClass(); 在一般意义的J

【java开发系列】—— 自定义注解(转)

之前在开发中,就总纳闷,为什么继承接口时,会出现@Override注解,有时候还会提示写注解@SuppressWarnings? 原来这是java特有的特性,注解! 那么什么是注解呢? 注解就是某种注解类型的一个实例,我们可以用它在某个类上进行标注,这样编译器在编译我们的文件时,会根据我们自己设定的方法来编译类. 注解都是什么呢?看下面这张图就明白了! 上面的图可以看出,注解大体上分为三种:标记注解,一般注解,元注解 这里面Override这个没测试出来,因为目前的Eclipse会自动帮我们排错

java基础知识:自定义注解

转自 深入了解注解 要深入学习注解,我们就必须能定义自己的注解,并使用注解,在定义自己的注解之前,我们就必须要了解Java为我们提供的元注解和相关定义注解的语法. 元注解的作用就是负责注解其他注解.Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明.Java5.0定义的元注解: [email protected], [email protected], [email protected], [email protected] 这

【java开发系列】—— 自定义注解

之前在开发中,就总纳闷,为什么继承接口时,会出现@Override注解,有时候还会提示写注解@SuppressWarnings? 原来这是java特有的特性,注解! 那么什么是注解呢? 注解就是某种注解类型的一个实例,我们可以用它在某个类上进行标注,这样编译器在编译我们的文件时,会根据我们自己设定的方法来编译类. 注解都是什么呢?看下面这张图就明白了! 上面的图可以看出,注解大体上分为三种:标记注解,一般注解,元注解 这里面Override这个没测试出来,因为目前的Eclipse会自动帮我们排错

AOP通过反射获取自定义注解

自定义注解: @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface DemoAnno { String value() default ""; } AOP: @Pointcut("@annotation(com.hephae.aop.aop.DemoAnno)") public void demoAspect

[原创]java WEB学习笔记15:域对象的属性操作(pageContext,request,session,application) 及 请求的重定向和转发

本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱好者,互联网技术发烧友 微博:伊直都在0221 QQ:951226918 ---------------------------------

java使用反射比较两个bean对象属性值是否相等

import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import org.apache.log4j.Logger; public class DomainEquals { /** * 日志操作类 */ private static Logger logger = Logger.getLogger(DomainEquals.c

java利用反射将pojo转为json对象

最近做以太坊钱包项目需要与前台进行json交互,写一个工具类,经普通javaBean转为json对象 1 package util; 2 3 import java.lang.reflect.Field; 4 import java.lang.reflect.Method; 5 import java.util.List; 6 7 import org.web3j.protocol.core.methods.response.Transaction; 8 9 import com.alibaba

使用Java反射(Reflect)、自定义注解(Customer Annotation)生成简单SQL语句

这次给大家介绍一下在Java开发过程中 使用自定义注解开发:主要知识点:            1.反射            主要用于提取注解信息            2.自定义异常  主要是为了自己自定义一个异常信息            3.自定义注解  本次重点 学会如何自定义注解以及如何使用反射提取注解信息运用到实际开发下图表示在Java中注解的含义以及注解的分类和如何解析注解 通常我们使用自定义注解一般使用4中元注解即:@Target@Retention@Documented@In