有没有可以“区分”两个对象的Java库?

问题描述:

是否有类似于Unix程序差异的Java实用程序库,但是对于对象?我正在寻找可以比较两个相同类型对象的东西,并生成一个表示它们之间差异的数据结构(并且可以递归地比较实例变量中的差异)。我是而不是寻找一个文本差异的Java实现。我也是而不是寻找如何使用反射做到这一点的帮助。有没有可以“区分”两个对象的Java库?

我正在维护的应用程序有一个脆弱的实现这个功能,有一些糟糕的设计选择,需要重写,但如果我们可以使用现成的东西会更好。

这里是我要找的那种东西的例子:

SomeClass a = new SomeClass(); 
SomeClass b = new SomeClass(); 

a.setProp1("A"); 
a.setProp2("X"); 

b.setProp1("B"); 
b.setProp2("X"); 

DiffDataStructure diff = OffTheShelfUtility.diff(a, b); // magical recursive comparison happens here 

比较后,程序会告诉我,“PROP1”是两个对象和“PROP2”之间的不同是相同的。我认为DiffDataStructure是一棵树是最自然的,但如果代码是可靠的,我不会挑剔。

+7

请查看http://code.google.com/p/jettison/ – denolk

+0

[如何测试复杂对象图的相等性?](http://*.com/questions/1411612/how -to-test-for-equal-of-complex-object-graphs) – skaffman

+7

这不是“如何测试复杂对象图的相等性?”的复制我正在寻找一个图书馆,而不是如何去做的建议。此外,我对三角洲感兴趣,如果他们平等或不平等的话。 –

也许这会有所帮助,这取决于你使用这段代码的地方,它可能是有用的或有问题的。测试了这个代码。

/** 
* @param firstInstance 
* @param secondInstance 
*/ 
protected static void findMatchingValues(SomeClass firstInstance, 
     SomeClass secondInstance) { 
    try { 
     Class firstClass = firstInstance.getClass(); 
     Method[] firstClassMethodsArr = firstClass.getMethods(); 

     Class secondClass = firstInstance.getClass(); 
     Method[] secondClassMethodsArr = secondClass.getMethods(); 


     for (int i = 0; i < firstClassMethodsArr.length; i++) { 
      Method firstClassMethod = firstClassMethodsArr[i]; 
      // target getter methods. 
      if(firstClassMethod.getName().startsWith("get") 
        && ((firstClassMethod.getParameterTypes()).length == 0) 
        && (!(firstClassMethod.getName().equals("getClass"))) 
      ){ 

       Object firstValue; 
        firstValue = firstClassMethod.invoke(firstInstance, null); 

       logger.info(" Value "+firstValue+" Method "+firstClassMethod.getName()); 

       for (int j = 0; j < secondClassMethodsArr.length; j++) { 
        Method secondClassMethod = secondClassMethodsArr[j]; 
        if(secondClassMethod.getName().equals(firstClassMethod.getName())){ 
         Object secondValue = secondClassMethod.invoke(secondInstance, null); 
         if(firstValue.equals(secondValue)){ 
          logger.info(" Values do match! "); 
         } 
        } 
       } 
      } 
     } 
     } catch (IllegalArgumentException e) { 
      e.printStackTrace(); 
     } catch (IllegalAccessException e) { 
      e.printStackTrace(); 
     } catch (InvocationTargetException e) { 
      e.printStackTrace(); 
     } 
} 
+1

谢谢,但我们已经有了使用反射列出更改的对象图形的代码。这个问题不是关于如何去做,而是试图避免重新发明*。 –

+0

如果重新发生已经发生,重新开车并不坏。 (IE:重新改造的车轮已经支付了。) –

+1

我同意你的看法,但在这种情况下,重新发明的代码是一个难以维系的混乱。 –

更简单的方法迅速告诉你,如果两个对象不同的是就是使用Apache Commons库

BeanComparator lastNameComparator = new BeanComparator("lname"); 
    logger.info(" Match "+bc.compare(firstInstance, secondInstance)); 
+0

这对我来说不起作用,因为我需要知道改变了什么,而不仅仅是改变某处。 –

可能有点晚,但我是在跟你同样的情况并最终为您的用例创建了自己的库。由于我自己不得不想出一个解决方案,所以我决定在Github上发布它,以免其他人付出艰辛的努力。你可以在这里找到它:https://github.com/SQiShER/java-object-diff

--- 编辑 ---

这里是一种基于有机磷农药代码有点用法示例:

SomeClass a = new SomeClass(); 
SomeClass b = new SomeClass(); 

a.setProp1("A"); 
a.setProp2("X"); 

b.setProp1("B"); 
b.setProp2("X"); 

DiffNode diff = ObjectDifferBuilder.buildDefault().compare(a, b); 

assert diff.hasChanges(); 
assert diff.childCount() == 1; 
assert diff.getChild('prop1').getState() == DiffNode.State.CHANGED; 
+1

我可以指点你这个帖子,显示java-object-diff的用例吗? http://*.com/questions/12104969/java-mongodb-object-versioning非常感谢这个有用的库! –

+0

我看了一下你的帖子,写了一个答案,结果太长了,不能发表评论,所以这里是它的“要点”:https://gist.github.com/3555555 – SQiShER

+2

整洁。我最终也写了我自己的实现。我不确定我会有机会真正探索你的实现,但我很好奇你如何处理列表。我最终将所有收集差异作为Maps的差异来处理(通过以不同的方式定义键,取决于它是列表,集合还是映射;然后对keySet使用set操作)。但是,该方法对列表索引更改过于敏感。我没有解决这个问题,因为我不需要为我的应用程序,但我很好奇你如何处理它(更像是一个文本差异,我会假设)。 –

http://javers.org是图书馆,做exacly什么你需要:像compare(Object leftGraph,Object rightGraph)这样的方法返回Diff对象。 Diff包含一系列更改(ReferenceChange,ValueChange,PropertyChange),例如

given: 
DummyUser user = dummyUser("id").withSex(FEMALE).build(); 
DummyUser user2 = dummyUser("id").withSex(MALE).build(); 
Javers javers = JaversTestBuilder.newInstance() 

when: 
Diff diff = javers.compare(user, user2) 

then: 
diff.changes.size() == 1 
ValueChange change = diff.changes[0] 
change.leftValue == FEMALE 
change.rightValue == MALE 

它可以在图形处理周期。

此外,您可以获得任何图形对象的快照。 Javers具有JSON序列化器和反序列化器来进行快照,并进行更改,以便您可以轻松地将它们保存在数据库中。有了这个库,您可以轻松实现审计模块。

+1

这不起作用。你如何创建一个Javers实例? –

+0

我也无法创建一个Javers实例。请给我们一些提示。 – marcel

+0

Javers具有优异的文档解释一切:[javers.org](http://javers.org/documentation/getting-started/#create-javers-instance) –

所有Javers库都只支持Java 7,因为我希望将它用于Java 6项目,所以我偶然采取了源代码并改变了它对Java 6的适用方式是github代码。

https://github.com/sand3sh/javers-forJava6

罐链接:https://github.com/sand3sh/javers-forJava6/blob/master/build/javers-forjava6.jar

我只是改变了Java 7的支持“<>”固有投转换为Java 6的支持 我不出示担保所有功能将工作,因为我有评论数对我来说不必要的代码适用于所有自定义对象的比较。

+0

Jar链接 - https://github.com/sand3sh/javers-forJava6/blob/master/build/javers-forjava6.jar – Sandesh

是的,java-util库有一个GraphComparator类,它将比较两个Java对象图。它将差异作为增量列表返回。 GraphComparator还允许您合并(应用)增量。这段代码只依赖于JDK,没有其他库。

+1

似乎一个不错的图书馆,你应该提到你是一个贡献者 – Christos