4

I am looking for a generic utility in Java, that can help me create a diff report for two objects (of the same type).

For instance, if my class structure is:

class A {
  int p1;
  string p2;
  B b1;
}

class B {
 float p3;
}

I want a report b/w two objects of type A (say, a1 and a2), as follows: a1 vs. a2

p1 : 'remove'
p2 : 'change'
b1.p3: 'add'

wherein, 'remove' is set if the property was null in the second object, 'change' if the properties were present but had different values, and 'add' if the property was null in the first object.

It may get tougher/trickier for collection objects...

Saket
  • 45,521
  • 12
  • 59
  • 79

6 Answers6

11

I created a library for that: https://github.com/SQiShER/java-object-diff

It builds a tree structure of your compared objects and allows you to traverse the nodes via visitor pattern. Take a look at the Getting Started page, to see some examples. It works with almost any kind of object and can handle as many nesting levels as you like. I even managed to build an automatic object merger based on it.

A printed version of such an object graph looks like this:

Property at path '/contacts/item[Walter White]/middleName' has been added => [ Hartwell ]
Property at path '/contacts/item[Jesse Pinkman]/middleName' has been added => [ Bruce ]

I'm using it myself and it works like a charm. Hope it helps!

I don't know how complex your objects are, but doing it manually via reflection gets out of hand rather quickly. Especially when Maps and Collections get involved.

SQiShER
  • 1,045
  • 7
  • 10
8

Javers is library that does exacly what you need:

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

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

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

It can handle cycles in graphs.

In addition you can get Snapshot of any graph object. Javers has JSON serializers and deserializers to snapshot, and changes, also has implemented storage in mongoDB.

Paweł Szymczyk
  • 1,638
  • 15
  • 20
  • What if the two objects that I compare has a list of objects internally and will I be seeing those differences too? What is the level of hierarchy that javers could compare? – Deepak Jul 20 '16 at 00:09
1

Take a look at this library I made. Maybe it can be useful to someone (supports diff/patch/compare with arbitrary deep object graphs and collections/maps/arrays)...

It should be simple to use:

GrandChildEntity gce1 = new GrandChildEntity(1);
GrandChildEntity gce2 = new GrandChildEntity(2);

Diff diff = new Diff.Builder().build();
Patch patch = new Patch.Builder().build();
Compare compare = new   Compare.Builder().build();

Element<Name, GrandChildEntity> diffElement = diff.diff(gce1, gce2);
GrandChildEntity patchedEntity = patch.patch(new GrandChildEntity(1), diffElement);
boolean areEqual = compare.compare(patchedEntity, new GrandChildEntity(2));

This is the link to github repo. (https://github.com/bojanv55/entity-sync-utils)

0

I doubt there is a generic utility to do that.

But that doesn't seem hard to write using java reflection API.

You can enumerate the fields of a class using

myClass.getFields();

So you just have to make a deep comparison.

Denys Séguret
  • 372,613
  • 87
  • 782
  • 758
0

Create sting representations of 2 objects using apache ToStringBuilder. Then compare strings.

Take a look on this discussion: How to perform string Diffs in Java?

It contains reference to library that performs textual diff in java.

Community
  • 1
  • 1
AlexR
  • 114,158
  • 16
  • 130
  • 208
0

You could use reflection API to achieve it.

I'm not giving the complete code. But this is one way you could start.

class Testapp {
    public static void main(String[] args) {
        A a1 = new A();
        A a2 = new A();
        a1.b1.p3 = 1;
        a1.p1 = 2;
        a1.p2 = "Hi";

        a2.b1.p3 = 1;
        a2.p1 = 3;
        a2.p2 = "Hi";

        Compare c = new Compare<A>(a1, a2);
        c.compare();
    }
}

class A
{
    int p1;
    String p2;
    B b1;
    A() {
        b1 = new B();
    }
}

class B {
    float p3;
}


class Compare<T extends Object> {
    T a;
    T b;
    public Compare(T a, T b)
    {
        this.a = a;
        this.b = b;
    }
    public void compare()
    {
        try
        {
            Field[] fields = a.getClass().getDeclaredFields();

            for (Field field : fields) {
                if(field.get(a)==field.get(b)){
                    //do something
                }
            }
        }catch(Exception e){}
    }
}
John Eipe
  • 10,922
  • 24
  • 72
  • 114