在两个bean中生成字段差异的常用算法?

假设您有两个相同bean类型的实例,并且您希望显示两个实例之间已更改内容的摘要 – 例如,您在应用程序中有一个表示用户设置的bean,并且您希望能够显示用户正在提交的新设置(实例#1)中已更改内容的列表与已为用户存储的内容(实例#2)的列表。

对于诸如此类的任务,是否存在常用的算法或设计模式,可能是可以抽象并重用于不同类型的bean的东西? (我很难想到这类问题的好名字,知道谷歌会怎么做)。 我检查过commons-beanutils,没有任何东西突然出现在我面前。

如果你在谈论比较值,我会考虑使用reflection并逐个比较它们。

像这样的东西:

Field[] oldFields = oldInstance.class.getDeclaredFields(); Field[] newFields = newInstance.class.getDeclaredFields(); StringBuilder changes = new StringBuilder(); Arrays.sort(oldFields); Arrays.sort(newFields); int i = 0; for(Field f : oldFields) { if(!f.equals(newFields[i])) { changes.append(f.getName()).append(" has changed.\n"); } i++; } 

此代码尚未经过测试。 您可能需要获取字段中的值并进行比较,而不是仅仅将字段相互比较,但它应该在理论上有效。

我们用bean utils做了类似的事情,效果很好。 需要考虑的事项:你是否深入研究了字段对象 – 如果一个Person包含一个地址并且地址发生了变化,你说地址是否已更改,或者地址.postalCode已更改(我们这样做)? 你从diff(我们这样做)返回一个列表propety名称,旧值,新值吗? 你想如何处理日期 – 如果你关心的只是日期部分,那么你的比较应该忽略时间? 怎么说哪些字段要忽略?

这不是一个真正的复制和粘贴答案,但更多的是在我们编写差异时并不是很明显的事情列表。

至于实现,我们只有一个静态util方法,它接受两个bean和一个要比较的属性列表,然后将属性映射返回给包含旧值和新值的Pair。 然后每个bean都有一个diff(Object o)方法,可以根据需要调用静态util方法。

这些库应该有所帮助。

https://code.google.com/p/beandiff/ – 基于注释的bean diffing库。 Apache License 2.0

https://github.com/SQiShER/java-object-diff/ – bean根据访客模式而不同。 Apache License 2.0

为了审计目的,我们要求以json格式生成bean之间的差异。 我们最终使用beandiff库实现它。

**编辑**这看起来像一个较新的选项。 我没有用过它。

http://beandiff.org/

希望能帮助到你。

reflection不会在下一次调用中保持Field的顺序:它是数组的安全顺序。

 /* *declarations of variables */ Arrays.sort(oldFields);//natural order - choice 1 Arrays.sort(newFields, new Ordinator());//custom Comparator - choice 2 /* *logic of comparations between elements */ 

在选择2中,您可以使用扩展比较器的内部类EQUator来决定排序逻辑(如何分类元素)。

PS代码是草稿

上面的好答案。

如果您的数据在结构上发生变化,即整个字段集合可能相关或不相关,则您可能需要考虑差异执行 。

基本上,您在字段上有一个循环,并且在反序列化先前值的同时序列化当前字段值,并在进行比较时进行比较。

如果存在使字段块相关或不相关的条件测试,则序列化/反序列化条件测试的真或假值,并使用它来决定是否序列化和/或反序列化受影响的字段。 它很好地复原了。

只是一个建议。

解决方案使用reflection和标准数据结构。

  Field[] declaredFields = ClassOne.class.getDeclaredFields(); Field[] declaredFields2 = ClassTwo.class.getDeclaredFields(); ArrayList one = new ArrayList(); ArrayList two = new ArrayList(); for (Field field : declaredFields) { one.add(field.getName()); } for (Field field : declaredFields2) { two.add(field.getName()); } List preone = (List)one.clone(); one.removeAll(two); two.removeAll(preone); Collections.sort(one); Collections.sort(two); System.out.println("fields only in One : " + one); System.out.println("fields only in Two : " + two);