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. jquery制作选项卡

    思路:点击按钮后,先让所有的按钮的class属性都为“”,所有的div的display样式都为none:再让当前被点击按钮的class属性为active,以及所对应的div的display样式为blo ...

  2. js最基础的作用域问题

    1.什么是作用域? 每个变量和函数,都有其作用的范围,超出这个范围,就不能使用了,这个范围就叫做“作用域”,我们举个例子,一个文件中的变,在另一个文件中直接访问,是访问不到的,两个文件是两个“域”,两 ...

  3. linux initcall机制

    Linux系统启动过程很复杂,因为它既需要支持模块静态加载机制也要支持动态加载机制.模块动态加载机制给系统提供了极大的灵活性,驱动程序既可支持静态编译进内核,也可以支持动态加载机制.Linux系统中对 ...

  4. Android代码混淆及项目发布方法记录

     Android代码混淆及项目发布步骤记录 本来整理了一份Android项目混淆与发布的文档,突然想到何不写篇博客,分享一下呢,如是便有了本文. Android代码混淆及项目发布步骤记录 一.清理 ...

  5. [置顶] Android开发百科全书

    友情提示根据目录 快速查找问题 %1$s %1$d Android string 1.整型,比如"我今年23岁了",这个23是整型的.在string.xml中可以这样写,<s ...

  6. 【解题报告】[动态规划] - PID90 / 未出现的子串

    原题地址:http://www.rqnoj.cn/problem/90 解题思路:题目看起来不太像动态规划... 我用一个数组f[i][j]来表示在数组第i个元素的后面第一次出现j的位置,为-1则是没 ...

  7. 排序算法总结(C#版)

    算法质量的衡量标准: 1:时间复杂度:分析关键字比较次数和记录的移动次数: 2:空间复杂度:需要的辅助内存: 3:稳定性:相同的关键字计算后,次序是否不变. 简单排序方法 .直接插入排序 直接插入排序 ...

  8. GIT多人合作开发

    . 建立代码仓库(专门用于团队开发的代码仓库) ============================================================================ ...

  9. 关于ORM,以及Python中SQLAlchemy的sessionmaker,scoped_session

    orm(object relational mapping):对象关系映射. python面向对象,而数据库是关系型. orm是将数据库关系映射为Python中的对象,不用直接写SQL. 缺点是性能略 ...

  10. poj 3128 Leonardo's Notebook——思路(置换)

    题目:http://poj.org/problem?id=3128 从环的角度考虑. 原来有奇数个点的环,现在点数不变: 原来有偶数个点的环(设有 k 个点),现在变成两个大小为 k/2 的环. 所以 ...