From d7705a491d72e45952e45179d869766e56864d9f Mon Sep 17 00:00:00 2001 From: Yuriy Barannikov Date: Thu, 23 Nov 2023 12:27:15 +0200 Subject: [PATCH] Add an ability to compare equals by equals() method objects with ReflectionDiffBuilder Useful when need to compare JPA entities with the same identifier --- .../lang3/builder/ReflectionDiffBuilder.java | 34 +++++++++++++++- .../builder/ReflectionDiffBuilderTest.java | 39 +++++++++++++++++++ 2 files changed, 71 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/apache/commons/lang3/builder/ReflectionDiffBuilder.java b/src/main/java/org/apache/commons/lang3/builder/ReflectionDiffBuilder.java index 785e08d598f..16d5f3072d5 100644 --- a/src/main/java/org/apache/commons/lang3/builder/ReflectionDiffBuilder.java +++ b/src/main/java/org/apache/commons/lang3/builder/ReflectionDiffBuilder.java @@ -75,6 +75,7 @@ public class ReflectionDiffBuilder implements Builder> { private final T left; private final T right; + private final boolean testTriviallyEqual; private final DiffBuilder diffBuilder; /** @@ -103,9 +104,38 @@ public class ReflectionDiffBuilder implements Builder> { * if {@code lhs} or {@code rhs} is {@code null} */ public ReflectionDiffBuilder(final T lhs, final T rhs, final ToStringStyle style) { + this(lhs, rhs, style, true); + } + + /** + * Constructs a builder for the specified objects with the specified style. + * + *

+ * If {@code lhs == rhs} or {@code lhs.equals(rhs)} then the builder will + * not evaluate any calls to {@code append(...)} and will return an empty + * {@link DiffResult} when {@link #build()} is executed. + *

+ * @param lhs + * {@code this} object + * @param rhs + * the object to diff against + * @param style + * the style will use when outputting the objects, {@code null} + * uses the default + * @param testTriviallyEqual + * If true, this will test if lhs and rhs are the same or equal. + * All of the append(fieldName, lhs, rhs) methods will abort + * without creating a field {@link Diff} if the trivially equal + * test is enabled and returns true. The result of this test + * is never changed throughout the life of this {@link ReflectionDiffBuilder} + * @throws IllegalArgumentException + * if {@code lhs} or {@code rhs} is {@code null} + */ + public ReflectionDiffBuilder(final T lhs, final T rhs, final ToStringStyle style, boolean testTriviallyEqual) { this.left = lhs; this.right = rhs; - this.diffBuilder = new DiffBuilder<>(lhs, rhs, style); + this.testTriviallyEqual = testTriviallyEqual; + this.diffBuilder = new DiffBuilder<>(lhs, rhs, style, testTriviallyEqual); } private boolean accept(final Field field) { @@ -143,7 +173,7 @@ private void appendFields(final Class clazz) { @Override public DiffResult build() { - if (left.equals(right)) { + if (testTriviallyEqual && left.equals(right)) { return diffBuilder.build(); } diff --git a/src/test/java/org/apache/commons/lang3/builder/ReflectionDiffBuilderTest.java b/src/test/java/org/apache/commons/lang3/builder/ReflectionDiffBuilderTest.java index f339e3cfa0d..d08943106f4 100644 --- a/src/test/java/org/apache/commons/lang3/builder/ReflectionDiffBuilderTest.java +++ b/src/test/java/org/apache/commons/lang3/builder/ReflectionDiffBuilderTest.java @@ -29,6 +29,31 @@ private static final class TypeTestChildClass extends TypeTestClass { String field = "a"; } + @SuppressWarnings("unused") + private static class TypeTestEntityClass implements Diffable { + + private Long id; + private String field1; + + @Override + public DiffResult diff(TypeTestEntityClass obj) { + return new ReflectionDiffBuilder(this, obj, SHORT_STYLE, false).build(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + TypeTestEntityClass that = (TypeTestEntityClass) obj; + return new EqualsBuilder().append(id, that.id).build(); + } + + @Override + public int hashCode() { + return new HashCodeBuilder(17, 37).append(id).toHashCode(); + } + } + @SuppressWarnings("unused") private static class TypeTestClass implements Diffable { private static int staticField; @@ -184,4 +209,18 @@ public void testGetExcludeFieldNamesWithNullValuesInExcludedFieldNames() { assertEquals("charField", excludeFieldNames[0]); } + @Test + public void testEqualsObjectDiff() { + final TypeTestEntityClass firstObject = new TypeTestEntityClass(); + firstObject.id = 1L; + firstObject.field1 = "a"; + + final TypeTestEntityClass secondObject = new TypeTestEntityClass(); + secondObject.id = 1L; + secondObject.field1 = "b"; + + final DiffResult list = firstObject.diff(secondObject); + assertEquals(1, list.getNumberOfDiffs()); + } + }