Skip to content

Commit daa8c6e

Browse files
author
Marc Cappelletti
committed
Add TypedEqualsBuilder class and test
1 parent 14be5e5 commit daa8c6e

File tree

3 files changed

+196
-21
lines changed

3 files changed

+196
-21
lines changed

src/main/java/org/apache/commons/lang3/builder/EqualsBuilder.java

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ private static void unregister(final Object lhs, final Object rhs) {
198198
* If the fields tested are equals.
199199
* The default value is {@code true}.
200200
*/
201-
private boolean isEquals = true;
201+
boolean isEquals = true;
202202

203203
private boolean testTransients;
204204
private boolean testRecursive;
@@ -450,6 +450,15 @@ public static boolean reflectionEquals(final Object lhs, final Object rhs, final
450450
.isEquals();
451451
}
452452

453+
/**
454+
* Indicates if an early append method leave should be done
455+
*
456+
* @return true if the equality is false
457+
*/
458+
boolean shouldLeaveEarly() {
459+
return !isEquals;
460+
}
461+
453462
/**
454463
* Tests if two {@code objects} by using reflection.
455464
*
@@ -478,7 +487,7 @@ public static boolean reflectionEquals(final Object lhs, final Object rhs, final
478487
* @return this
479488
*/
480489
public EqualsBuilder reflectionAppend(final Object lhs, final Object rhs) {
481-
if (!isEquals) {
490+
if (shouldLeaveEarly()) {
482491
return this;
483492
}
484493
if (lhs == rhs) {
@@ -583,7 +592,7 @@ private void reflectionAppend(
583592
* @since 2.0
584593
*/
585594
public EqualsBuilder appendSuper(final boolean superEquals) {
586-
if (!isEquals) {
595+
if (shouldLeaveEarly()) {
587596
return this;
588597
}
589598
isEquals = superEquals;
@@ -602,7 +611,7 @@ public EqualsBuilder appendSuper(final boolean superEquals) {
602611
* @return this
603612
*/
604613
public EqualsBuilder append(final Object lhs, final Object rhs) {
605-
if (!isEquals) {
614+
if (shouldLeaveEarly()) {
606615
return this;
607616
}
608617
if (lhs == rhs) {
@@ -670,7 +679,7 @@ private void appendArray(final Object lhs, final Object rhs) {
670679
* @return this
671680
*/
672681
public EqualsBuilder append(final long lhs, final long rhs) {
673-
if (!isEquals) {
682+
if (shouldLeaveEarly()) {
674683
return this;
675684
}
676685
isEquals = lhs == rhs;
@@ -685,7 +694,7 @@ public EqualsBuilder append(final long lhs, final long rhs) {
685694
* @return this
686695
*/
687696
public EqualsBuilder append(final int lhs, final int rhs) {
688-
if (!isEquals) {
697+
if (shouldLeaveEarly()) {
689698
return this;
690699
}
691700
isEquals = lhs == rhs;
@@ -700,7 +709,7 @@ public EqualsBuilder append(final int lhs, final int rhs) {
700709
* @return this
701710
*/
702711
public EqualsBuilder append(final short lhs, final short rhs) {
703-
if (!isEquals) {
712+
if (shouldLeaveEarly()) {
704713
return this;
705714
}
706715
isEquals = lhs == rhs;
@@ -715,7 +724,7 @@ public EqualsBuilder append(final short lhs, final short rhs) {
715724
* @return this
716725
*/
717726
public EqualsBuilder append(final char lhs, final char rhs) {
718-
if (!isEquals) {
727+
if (shouldLeaveEarly()) {
719728
return this;
720729
}
721730
isEquals = lhs == rhs;
@@ -730,7 +739,7 @@ public EqualsBuilder append(final char lhs, final char rhs) {
730739
* @return this
731740
*/
732741
public EqualsBuilder append(final byte lhs, final byte rhs) {
733-
if (!isEquals) {
742+
if (shouldLeaveEarly()) {
734743
return this;
735744
}
736745
isEquals = lhs == rhs;
@@ -751,7 +760,7 @@ public EqualsBuilder append(final byte lhs, final byte rhs) {
751760
* @return this
752761
*/
753762
public EqualsBuilder append(final double lhs, final double rhs) {
754-
if (!isEquals) {
763+
if (shouldLeaveEarly()) {
755764
return this;
756765
}
757766
return append(Double.doubleToLongBits(lhs), Double.doubleToLongBits(rhs));
@@ -771,7 +780,7 @@ public EqualsBuilder append(final double lhs, final double rhs) {
771780
* @return this
772781
*/
773782
public EqualsBuilder append(final float lhs, final float rhs) {
774-
if (!isEquals) {
783+
if (shouldLeaveEarly()) {
775784
return this;
776785
}
777786
return append(Float.floatToIntBits(lhs), Float.floatToIntBits(rhs));
@@ -785,7 +794,7 @@ public EqualsBuilder append(final float lhs, final float rhs) {
785794
* @return this
786795
*/
787796
public EqualsBuilder append(final boolean lhs, final boolean rhs) {
788-
if (!isEquals) {
797+
if (shouldLeaveEarly()) {
789798
return this;
790799
}
791800
isEquals = lhs == rhs;
@@ -806,7 +815,7 @@ public EqualsBuilder append(final boolean lhs, final boolean rhs) {
806815
* @return this
807816
*/
808817
public EqualsBuilder append(final Object[] lhs, final Object[] rhs) {
809-
if (!isEquals) {
818+
if (shouldLeaveEarly()) {
810819
return this;
811820
}
812821
if (lhs == rhs) {
@@ -837,7 +846,7 @@ public EqualsBuilder append(final Object[] lhs, final Object[] rhs) {
837846
* @return this
838847
*/
839848
public EqualsBuilder append(final long[] lhs, final long[] rhs) {
840-
if (!isEquals) {
849+
if (shouldLeaveEarly()) {
841850
return this;
842851
}
843852
if (lhs == rhs) {
@@ -868,7 +877,7 @@ public EqualsBuilder append(final long[] lhs, final long[] rhs) {
868877
* @return this
869878
*/
870879
public EqualsBuilder append(final int[] lhs, final int[] rhs) {
871-
if (!isEquals) {
880+
if (shouldLeaveEarly()) {
872881
return this;
873882
}
874883
if (lhs == rhs) {
@@ -899,7 +908,7 @@ public EqualsBuilder append(final int[] lhs, final int[] rhs) {
899908
* @return this
900909
*/
901910
public EqualsBuilder append(final short[] lhs, final short[] rhs) {
902-
if (!isEquals) {
911+
if (shouldLeaveEarly()) {
903912
return this;
904913
}
905914
if (lhs == rhs) {
@@ -930,7 +939,7 @@ public EqualsBuilder append(final short[] lhs, final short[] rhs) {
930939
* @return this
931940
*/
932941
public EqualsBuilder append(final char[] lhs, final char[] rhs) {
933-
if (!isEquals) {
942+
if (shouldLeaveEarly()) {
934943
return this;
935944
}
936945
if (lhs == rhs) {
@@ -961,7 +970,7 @@ public EqualsBuilder append(final char[] lhs, final char[] rhs) {
961970
* @return this
962971
*/
963972
public EqualsBuilder append(final byte[] lhs, final byte[] rhs) {
964-
if (!isEquals) {
973+
if (shouldLeaveEarly()) {
965974
return this;
966975
}
967976
if (lhs == rhs) {
@@ -992,7 +1001,7 @@ public EqualsBuilder append(final byte[] lhs, final byte[] rhs) {
9921001
* @return this
9931002
*/
9941003
public EqualsBuilder append(final double[] lhs, final double[] rhs) {
995-
if (!isEquals) {
1004+
if (shouldLeaveEarly()) {
9961005
return this;
9971006
}
9981007
if (lhs == rhs) {
@@ -1023,7 +1032,7 @@ public EqualsBuilder append(final double[] lhs, final double[] rhs) {
10231032
* @return this
10241033
*/
10251034
public EqualsBuilder append(final float[] lhs, final float[] rhs) {
1026-
if (!isEquals) {
1035+
if (shouldLeaveEarly()) {
10271036
return this;
10281037
}
10291038
if (lhs == rhs) {
@@ -1054,7 +1063,7 @@ public EqualsBuilder append(final float[] lhs, final float[] rhs) {
10541063
* @return this
10551064
*/
10561065
public EqualsBuilder append(final boolean[] lhs, final boolean[] rhs) {
1057-
if (!isEquals) {
1066+
if (shouldLeaveEarly()) {
10581067
return this;
10591068
}
10601069
if (lhs == rhs) {
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.commons.lang3.builder;
18+
19+
import java.util.Objects;
20+
import java.util.function.Function;
21+
22+
/**
23+
* An extension of {@link EqualsBuilder} aimed to perform additionally the base objects and class equals checks.
24+
*
25+
* <p>It then offers the possibility to append field extractors.</p>
26+
*
27+
* <p>Typical use for the code is as follows:</p>
28+
* <pre>
29+
* public boolean equals(Object obj) {
30+
* return new TypedEqualsBuilder<>(this)
31+
* .appendBaseObject(obj)
32+
* .append(TestObject::getA)
33+
* .append(TestObject::getB)
34+
* .isEquals();
35+
* }
36+
* </pre>
37+
*
38+
* @param <T> the type of the compared object.
39+
*
40+
* @since 3.14.0
41+
*/
42+
public class TypedEqualsBuilder<T> extends EqualsBuilder {
43+
44+
private final T currentInstance;
45+
46+
private boolean sameReference = false;
47+
private T other;
48+
49+
@SuppressWarnings("unchecked")
50+
public TypedEqualsBuilder(T currentInstance, Object other) {
51+
Objects.requireNonNull(currentInstance);
52+
this.currentInstance = currentInstance;
53+
if (currentInstance == other) {
54+
sameReference = true;
55+
return;
56+
}
57+
Class<T> currentInstanceClass = (Class<T>) currentInstance.getClass();
58+
if (other == null || currentInstanceClass != other.getClass()) {
59+
isEquals = false;
60+
return;
61+
}
62+
this.other = (T) other;
63+
}
64+
65+
@Override
66+
boolean shouldLeaveEarly() {
67+
return sameReference || super.shouldLeaveEarly();
68+
}
69+
70+
public TypedEqualsBuilder<T> append(Function<T, ?> extractor) {
71+
if (shouldLeaveEarly()) {
72+
return this;
73+
}
74+
super.append(extractor.apply(currentInstance), extractor.apply(other));
75+
return this;
76+
}
77+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.commons.lang3.builder;
18+
19+
import org.junit.jupiter.api.Test;
20+
21+
import static org.junit.jupiter.api.Assertions.*;
22+
23+
class TypedEqualsBuilderTest {
24+
25+
@Test
26+
void test_complete_equals() {
27+
TestObject testObject1 = new TestObject(1, 2);
28+
TestObject testObject2 = new TestObject(1, 3);
29+
TestObject testObject3 = new TestObject(1, 2);
30+
31+
assertEquals(testObject1, testObject1);
32+
assertNotEquals(testObject1, testObject2);
33+
assertNotEquals(testObject2, testObject1);
34+
35+
assertEquals(Boolean.TRUE,
36+
new TypedEqualsBuilder<>(testObject1, testObject2)
37+
.append(TestObject::getA)
38+
.isEquals());
39+
assertEquals(Boolean.TRUE,
40+
new TypedEqualsBuilder<>(testObject1, testObject3)
41+
.append(TestObject::getA)
42+
.append(TestObject::getB)
43+
.isEquals());
44+
assertEquals(Boolean.FALSE,
45+
new TypedEqualsBuilder<>(testObject1, testObject2)
46+
.append(TestObject::getA)
47+
.append(TestObject::getB)
48+
.isEquals());
49+
assertEquals(Boolean.FALSE,
50+
new TypedEqualsBuilder<>(testObject2, testObject1)
51+
.append(TestObject::getA)
52+
.append(TestObject::getB)
53+
.isEquals());
54+
assertEquals(Boolean.FALSE,
55+
new TypedEqualsBuilder<>(testObject1, null)
56+
.append(TestObject::getA)
57+
.isEquals());
58+
assertEquals(Boolean.FALSE,
59+
new TypedEqualsBuilder<>(testObject1, "")
60+
.append(TestObject::getA)
61+
.isEquals());
62+
}
63+
64+
static class TestObject {
65+
int a;
66+
int b;
67+
68+
public TestObject(int a, int b) {
69+
this.a = a;
70+
this.b = b;
71+
}
72+
73+
public int getA() {
74+
return a;
75+
}
76+
77+
public int getB() {
78+
return b;
79+
}
80+
81+
@Override
82+
public boolean equals(Object obj) {
83+
return new TypedEqualsBuilder<>(this, obj)
84+
.append(TestObject::getA)
85+
.append(TestObject::getB)
86+
.isEquals();
87+
}
88+
}
89+
}

0 commit comments

Comments
 (0)