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

时间:2011-11-03 20:25:30

标签: java diff

是否存在类似于Unix程序diff的Java实用程序库,但对于Objects?我正在寻找可以比较两个相同类型的对象并生成表示它们之间差异的数据结构的东西(并且可以递归地比较实例变量中的差异)。我正在寻找文本差异的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 个答案:

答案 0 :(得分:36)

可能会有点晚,但我和你一样处于同样的境地,最终创建了我自己的库,以确定你的用例。由于我自己被迫提出解决方案,我决定在Github上发布它,以免其他人付出辛苦的努力。您可以在此处找到它:https://github.com/SQiShER/java-object-diff

--- 修改 ---

这是一个基于OP代码的小用法示例:

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 :(得分:27)

http://javers.org是一个可以满足你需要的库:像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序列化器和反序列化器来快照和更改,因此您可以轻松地将它们保存在数据库中。使用此库,您可以轻松实现用于审核的模块。

答案 2 :(得分:7)

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

答案 3 :(得分:3)

所有Javers库都只支持Java 7,因为我希望将它用于Java 6项目所以我处于这种情况所以我碰巧采用了源代码并改变了它适用于Java 6的方式,下面是github代码。

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

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

我只更改了受支持的Java 7'<>'固有的转换为Java 6支持 我不保证所有的功能都会起作用,因为我已经为我评论了一些不必要的代码,它适用于所有自定义对象的比较。

答案 4 :(得分:1)

也许这会有所帮助,取决于您使用此代码的位置,它可能有用或有问题。测试了这段代码。

    /**
 * @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();
        }
}

答案 5 :(得分:0)

您还可以查看Apache的解决方案。 自从commons-lang以来,大多数项目已经在其类路径中使用了它。

检查特定字段的差异:
http://commons.apache.org/proper/commons-lang/javadocs/api-3.9/org/apache/commons/lang3/builder/DiffBuilder.html

通过反射检查差异:
http://commons.apache.org/proper/commons-lang/javadocs/api-3.9/org/apache/commons/lang3/builder/ReflectionDiffBuilder.html

答案 6 :(得分:-3)

一种更简单的方法可以快速告诉您两个对象是否不同将是使用apache commons库

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