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

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

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

  1. java 利用反射完成自定义注解

    元注解: 元注解的作用就是负责注解其他注解.Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明.Java5.0定义的元注解: 1.@ ...

  2. 利用反射跟自定义注解拼接实体对象的查询SQL

    前言 项目中虽然有ORM映射框架来帮我们拼写SQL,简化开发过程,降低开发难度.但难免会出现需要自己拼写SQL的情况,这里分享一个利用反射跟自定义注解拼接实体对象的查询SQL的方法. 代码 自定义注解 ...

  3. Android面试基础(一)IOC(DI)框架(ViewUtils)讲解_反射和自定义注解类

    1. Android中的IOC(DI)框架 1.1 ViewUtils简介(xUtils中的四大部分之一) IOC: Inverse of Controller 控制反转. DI: Dependenc ...

  4. Java反射与自定义注解

    反射,在Java常用框架中屡见不鲜.它存在于java.lang.reflact包中,就我的认识,它可以拿到类的字段和方法,及构造方法,还可以生成对象实例等.对深入的机制我暂时还不了解,本篇文章着重在使 ...

  5. java基础知识:自定义注解

    转自 深入了解注解 要深入学习注解,我们就必须能定义自己的注解,并使用注解,在定义自己的注解之前,我们就必须要了解Java为我们提供的元注解和相关定义注解的语法. 元注解的作用就是负责注解其他注解.J ...

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

    之前在开发中,就总纳闷,为什么继承接口时,会出现@Override注解,有时候还会提示写注解@SuppressWarnings? 原来这是java特有的特性,注解! 那么什么是注解呢? 注解就是某种注 ...

  7. JAVA中如何定义自定义注解

    了解注解 注解是Java1.5,JDK5.0引用的技术,与类,接口,枚举处于同一层次 .它可以声明在包.类.字段.方法.局部变量.方法参数等的前面,用来对这些元素进行说明,注释 . 在Java中,自带 ...

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

    自定义注解: @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component publ ...

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

    本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...

随机推荐

  1. Intent Flag启动模式P203

    Activity启动模式:点此查看 Intent intent = new Intent(); /** * Intent.FLAG_ACTIVITY_NEW_TASK * 使用一个新的Task来启动一 ...

  2. 解决AndroidStudio导入项目在 Building gradle project info 一直卡住

    Android Studio导入项目的时候,一直卡在Building gradle project info这一步,主要原因还是因为被墙的结果.gradle官网虽然可以访问,但是速度连蜗牛都赶不上.. ...

  3. Android onTouchEvent和setOnTouchListener中onTouch的区别

    OnTouchEvent()方法 是获取的对屏幕的各种操作,比如向左向右滑动,点击返回按钮等等. 属于一个宏观的屏幕触摸监控. OnTouchListener()方法 是获取某一个控件某一个View的 ...

  4. ng 动态的生成option。

    ngOptions:根据集合,动态的生成option. select ng-options="color.name for color in colorList" 注意跟ng-re ...

  5. Bootstrap和IE何时能相亲相爱啊~

    公司新项目,嘚瑟了一下,用了用Bootstrap... ... 发现了一个小坑(也许只是对我而言)... ... 使用了2.x的Jquery,在chrome等高版本浏览器一切顺利... ... 然,3 ...

  6. HDU - 233 Matrix

    原题地址:http://acm.hdu.edu.cn/showproblem.php?pid=5015 解题思路:一看到题目,感觉是杨辉三角形,然后用组合数学做,不过没想出来怎么做,后来看数据+递推思 ...

  7. eclipse导出文件上传服务器

    [1]导出     选择项目    文件导出 输入导出路径如f盘ftp文件夹下 [2]利用scr上传服务器工具 上传到 home/tomcat/app/项目名称/ 不导入upload文件 [待完善]

  8. jstl错误排除:According to TLD or attribute directive in tag file, attribute value does not accept any expressions

    问题描述: 在 JSP 页面中使用 JSTL 标签库,访问 JSP 页面时抛出了如下异常信息: org.apache.jasper.JasperException: /index.jsp (line: ...

  9. hadoop复合键排序使用方法

    在hadoop中处理复杂业务时,需要用到复合键,复合不同于单纯的继承Writable接口,而是继承了 WritableComparable<T>接口,而实际上,WritableCompar ...

  10. 省略名词: 从 Please find the attached 说起

    为什么是attached 首先需要解释的,为什么是叫attached: When you would like a person to reference a document attached to ...