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. 【.Net】Socket小示例

    引言 项目中用到了Socket,这里做个控制台小示例记录一下. Client 客户端的Receive用了异步方法,保持长连接,可以随时发送消息和响应服务端的消息,如下 static string Cl ...

  2. MongoCola使用教程 2 - MongoDB的Replset 初始化和配置

    前言 首先再次感谢博客园的各位朋友.正是你们的关注才让我有信心将这个工具开发下去. 这周同样也有热心网友对于MongoCola存在的问题给予了反馈. 这次工具更新到了版本1.20,强化的地方是增加了R ...

  3. 内存保护机制及绕过方案——通过覆盖SEH异常处理函数绕过/GS机制

    通过SEH链绕过GS保护机制 ⑴.  原理分析: i.异常处理结构(SEH)处理流程如下: SEH是基于线程的,每一个线程都有一个独立的SEH处理结果,在线程信息块中的第一个结构指向线程的异常列表,F ...

  4. OC-如何隐藏NSLog打印的自带信息

    #ifdef DEBUG #define NSLog(FORMAT, ...) fprintf(stderr,"%s\n",[[NSString stringWithFormat: ...

  5. 假如数组接收到一个null,那么应该怎么循环输出。百度结果,都需要提前判断。否则出现空指针异常。。我还是想在数组中实现保存和输出null。

    假如数组接收到一个null,那么应该怎么循环输出.因为foreach与obj.length都会报错.null不是对象,foreach中不能赋值? sp页面forEach一个存放对象的集合,怎么判断其中 ...

  6. New Concept English three (27)

    35w/m 67 It has been said that everyone lives by selling something. In the light of this statement, ...

  7. 【python】使用asyncore进行异步通信

    参考博文:http://blog.csdn.net/livefun/article/details/8721772 参考博文:https://www.cnblogs.com/tomato0906/ar ...

  8. java事务(三)——自己实现分布式事务

    在上一篇<java事务(二)——本地事务>中已经提到了事务的类型,并对本地事务做了说明.而分布式事务是跨越多个数据源来对数据来进行访问和更新,在JAVA中是使用JTA(Java Trans ...

  9. 6.etc目录下重要文件和目录详解

    1./etc/下的重要的配置文件 /etc(二进制软件包的 yum /rpm 安装的软件和所有系统管理所需要的配置文件和子目录.还有安装的服务的启动命令也放置在此处) /etc/sysconfig/n ...

  10. 使用Kali Linux执行中间人攻击(演示)

    中间人攻击也叫Man-In-The-Middle-Attack. 我假设你已经知道中间人攻击的基本概念,引用一段wikipedia: 中间人攻击(Man-in-the-middle attack,缩写 ...