Might be a little late, but I was in the same situation like you and ended up creating my own library for exactly your use-case. Since I was forced to come up with a solution myself, I decided to release it on Github, to spare others the hard work. You can find it here: https://github.com/SQiShER/java-object-diff
--- Edit ---
Here is a little usage example based on the OPs code:
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;
Answer from SQiShER on Stack OverflowVideos
Might be a little late, but I was in the same situation like you and ended up creating my own library for exactly your use-case. Since I was forced to come up with a solution myself, I decided to release it on Github, to spare others the hard work. You can find it here: https://github.com/SQiShER/java-object-diff
--- Edit ---
Here is a little usage example based on the OPs code:
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;
http://javers.org is library that does exacly what you need: has methods like compare(Object leftGraph, Object rightGraph) returning the Diff object. Diff contains a list of changes (ReferenceChange, ValueChange, PropertyChange) e.g.
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
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 so you can easily save them in database. With this library you can easily implement a module for auditing.
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.
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.