Reputation: 701
We try to use Appache commons DiffBuilder
and also ReflectionDiffBuilder
in version 3.7` to compare two complex objects each other.
For a simple object it is working really good, but I'm not able to get it work with properties which are an List of other Complex Objects which could contain again a complex object.
Let me explain better, if we have for Example this object (we will represent it for simplicity by an json object):
{
"id": 1,
"name": "Master1",
"details": [{
"id": 1,
"name": "Master1.Detail1"
}, {
"id": 2,
"name": "Master2.Detail2",
"subDetail": [{
"id1": 1,
"name": "Master2.Detail2.SubDetail1"
}]
}]
}
In This Case if we change name
in SubDetail1
and compare old with new object we need also to be notified that the property in the third level of 3 complex objects changed.
Is this possible with Apaches library? It seems not out of the box?
Upvotes: 3
Views: 2168
Reputation: 11
In your parent diff method you should iterate through your collections and compare each sub entities and append all differences in your parent diff result object. source
for (int i = 0; i < first.getDetails().size(); i++) {
diffBuilder.append("details[" + i + "].name",
first.getDetails().get(i).getName(),
second.getDetails().get(i).getName());
}
You may need to have the Detail object implement Diffable as well if it is more complex
for (int i = 0; i < first.getDetails().size(); i++) {
diffBuilder.append("details[" + i + "]",
first.getDetails().get(i).diff(second.getDetails().get(i)));
}
Granted This all assumes that the items in the list remain a certain set, and we are merely comparing the items by index. If however the list changes via removals or additions the standard behavior of the ReflectionDiffBuilder can detect said changes to the List as a whole and you can interpret the results afterward.
original.diff(changed).getDiffs().stream()
.flatMap(
diff -> {
if (diff.getLeft() instanceof Collection<?>) {
return Stream.of(
"%s dropped %s"
.formatted(
diff.getFieldName(),
CollectionUtils.removeAll(
(Collection<?>) diff.getLeft(), (Collection<?>) diff.getRight())),
"%s added %s"
.formatted(
diff.getFieldName(),
CollectionUtils.removeAll(
(Collection<?>) diff.getRight(), (Collection<?>) diff.getLeft())));
} else {
return Stream.of(
"%s changed from %s to %s"
.formatted(
diff.getFieldName(), diff.getLeft().toString(), diff.getRight()));
}
})
.toList();
Or finally Example 2 here makes creative use of the limitation that we could learn from
@lombok.Value
public class DiffableCollectionHolder<T> implements Diffable<Collection<T>> {
Collection<T> collection;
public DiffResult<Collection<T>> diff(Collection<T> obj) {
return DiffBuilder.<Collection<T>>builder().setLeft(this.getCollection())
.setRight(obj).build()
.append("removals", Collections.emptyList(), CollectionUtils.removeAll(this.getCollection(), obj))
.append("additions", Collections.emptyList(), CollectionUtils.removeAll(obj, this.getCollection())).build();
}
}
Upvotes: -1