Skip to content

Commit

Permalink
https://issues.apache.org/jira/browse/LANG-1712
Browse files Browse the repository at this point in the history
Add TypedEqualsBuilder class and test
  • Loading branch information
Marc Cappelletti committed Sep 27, 2023
1 parent 14be5e5 commit 602c964
Show file tree
Hide file tree
Showing 3 changed files with 210 additions and 22 deletions.
53 changes: 31 additions & 22 deletions src/main/java/org/apache/commons/lang3/builder/EqualsBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -195,10 +195,10 @@ private static void unregister(final Object lhs, final Object rhs) {
}

/**
* If the fields tested are equals.
* If the fields tested are equal
* The default value is {@code true}.
*/
private boolean isEquals = true;
protected boolean isEquals = true;

private boolean testTransients;
private boolean testRecursive;
Expand Down Expand Up @@ -450,6 +450,15 @@ public static boolean reflectionEquals(final Object lhs, final Object rhs, final
.isEquals();
}

/**
* Indicates if we should interrupt the comparison during an appending.
*
* @return true if the equality is false
*/
boolean interruptEqualityCheck() {
return !isEquals;
}

/**
* Tests if two {@code objects} by using reflection.
*
Expand Down Expand Up @@ -478,7 +487,7 @@ public static boolean reflectionEquals(final Object lhs, final Object rhs, final
* @return this
*/
public EqualsBuilder reflectionAppend(final Object lhs, final Object rhs) {
if (!isEquals) {
if (interruptEqualityCheck()) {
return this;
}
if (lhs == rhs) {
Expand Down Expand Up @@ -583,7 +592,7 @@ private void reflectionAppend(
* @since 2.0
*/
public EqualsBuilder appendSuper(final boolean superEquals) {
if (!isEquals) {
if (interruptEqualityCheck()) {
return this;
}
isEquals = superEquals;
Expand All @@ -602,7 +611,7 @@ public EqualsBuilder appendSuper(final boolean superEquals) {
* @return this
*/
public EqualsBuilder append(final Object lhs, final Object rhs) {
if (!isEquals) {
if (interruptEqualityCheck()) {
return this;
}
if (lhs == rhs) {
Expand Down Expand Up @@ -670,7 +679,7 @@ private void appendArray(final Object lhs, final Object rhs) {
* @return this
*/
public EqualsBuilder append(final long lhs, final long rhs) {
if (!isEquals) {
if (interruptEqualityCheck()) {
return this;
}
isEquals = lhs == rhs;
Expand All @@ -685,7 +694,7 @@ public EqualsBuilder append(final long lhs, final long rhs) {
* @return this
*/
public EqualsBuilder append(final int lhs, final int rhs) {
if (!isEquals) {
if (interruptEqualityCheck()) {
return this;
}
isEquals = lhs == rhs;
Expand All @@ -700,7 +709,7 @@ public EqualsBuilder append(final int lhs, final int rhs) {
* @return this
*/
public EqualsBuilder append(final short lhs, final short rhs) {
if (!isEquals) {
if (interruptEqualityCheck()) {
return this;
}
isEquals = lhs == rhs;
Expand All @@ -715,7 +724,7 @@ public EqualsBuilder append(final short lhs, final short rhs) {
* @return this
*/
public EqualsBuilder append(final char lhs, final char rhs) {
if (!isEquals) {
if (interruptEqualityCheck()) {
return this;
}
isEquals = lhs == rhs;
Expand All @@ -730,7 +739,7 @@ public EqualsBuilder append(final char lhs, final char rhs) {
* @return this
*/
public EqualsBuilder append(final byte lhs, final byte rhs) {
if (!isEquals) {
if (interruptEqualityCheck()) {
return this;
}
isEquals = lhs == rhs;
Expand All @@ -751,7 +760,7 @@ public EqualsBuilder append(final byte lhs, final byte rhs) {
* @return this
*/
public EqualsBuilder append(final double lhs, final double rhs) {
if (!isEquals) {
if (interruptEqualityCheck()) {
return this;
}
return append(Double.doubleToLongBits(lhs), Double.doubleToLongBits(rhs));
Expand All @@ -771,7 +780,7 @@ public EqualsBuilder append(final double lhs, final double rhs) {
* @return this
*/
public EqualsBuilder append(final float lhs, final float rhs) {
if (!isEquals) {
if (interruptEqualityCheck()) {
return this;
}
return append(Float.floatToIntBits(lhs), Float.floatToIntBits(rhs));
Expand All @@ -785,7 +794,7 @@ public EqualsBuilder append(final float lhs, final float rhs) {
* @return this
*/
public EqualsBuilder append(final boolean lhs, final boolean rhs) {
if (!isEquals) {
if (interruptEqualityCheck()) {
return this;
}
isEquals = lhs == rhs;
Expand All @@ -806,7 +815,7 @@ public EqualsBuilder append(final boolean lhs, final boolean rhs) {
* @return this
*/
public EqualsBuilder append(final Object[] lhs, final Object[] rhs) {
if (!isEquals) {
if (interruptEqualityCheck()) {
return this;
}
if (lhs == rhs) {
Expand Down Expand Up @@ -837,7 +846,7 @@ public EqualsBuilder append(final Object[] lhs, final Object[] rhs) {
* @return this
*/
public EqualsBuilder append(final long[] lhs, final long[] rhs) {
if (!isEquals) {
if (interruptEqualityCheck()) {
return this;
}
if (lhs == rhs) {
Expand Down Expand Up @@ -868,7 +877,7 @@ public EqualsBuilder append(final long[] lhs, final long[] rhs) {
* @return this
*/
public EqualsBuilder append(final int[] lhs, final int[] rhs) {
if (!isEquals) {
if (interruptEqualityCheck()) {
return this;
}
if (lhs == rhs) {
Expand Down Expand Up @@ -899,7 +908,7 @@ public EqualsBuilder append(final int[] lhs, final int[] rhs) {
* @return this
*/
public EqualsBuilder append(final short[] lhs, final short[] rhs) {
if (!isEquals) {
if (interruptEqualityCheck()) {
return this;
}
if (lhs == rhs) {
Expand Down Expand Up @@ -930,7 +939,7 @@ public EqualsBuilder append(final short[] lhs, final short[] rhs) {
* @return this
*/
public EqualsBuilder append(final char[] lhs, final char[] rhs) {
if (!isEquals) {
if (interruptEqualityCheck()) {
return this;
}
if (lhs == rhs) {
Expand Down Expand Up @@ -961,7 +970,7 @@ public EqualsBuilder append(final char[] lhs, final char[] rhs) {
* @return this
*/
public EqualsBuilder append(final byte[] lhs, final byte[] rhs) {
if (!isEquals) {
if (interruptEqualityCheck()) {
return this;
}
if (lhs == rhs) {
Expand Down Expand Up @@ -992,7 +1001,7 @@ public EqualsBuilder append(final byte[] lhs, final byte[] rhs) {
* @return this
*/
public EqualsBuilder append(final double[] lhs, final double[] rhs) {
if (!isEquals) {
if (interruptEqualityCheck()) {
return this;
}
if (lhs == rhs) {
Expand Down Expand Up @@ -1023,7 +1032,7 @@ public EqualsBuilder append(final double[] lhs, final double[] rhs) {
* @return this
*/
public EqualsBuilder append(final float[] lhs, final float[] rhs) {
if (!isEquals) {
if (interruptEqualityCheck()) {
return this;
}
if (lhs == rhs) {
Expand Down Expand Up @@ -1054,7 +1063,7 @@ public EqualsBuilder append(final float[] lhs, final float[] rhs) {
* @return this
*/
public EqualsBuilder append(final boolean[] lhs, final boolean[] rhs) {
if (!isEquals) {
if (interruptEqualityCheck()) {
return this;
}
if (lhs == rhs) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.lang3.builder;

import org.apache.commons.lang3.function.FailableFunction;

import java.util.Objects;
import java.util.function.Function;

/**
* An extension of {@link EqualsBuilder} that is typed and meant to append field getter functions.
* it does the nullity and class equality checks before checking the appended values.
*
* <p>Typical use for the code is as follows:</p>
* <pre>
* public boolean equals(Object obj) {
* return new TypedEqualsBuilder&lt;&gt;(this)
* .appendBaseObject(obj)
* .append(TestObject::getA)
* .append(TestObject::getB)
* .isEquals();
* }
* </pre>
*
* @param <T> the type of the compared object.
*
* @since 3.14.0
*/
public class TypedEqualsBuilder<T> extends EqualsBuilder {

private final T currentInstance;

private boolean sameReference = false;
private T other;

@SuppressWarnings("unchecked")
public TypedEqualsBuilder(T currentInstance, Object other) {
Objects.requireNonNull(currentInstance);
this.currentInstance = currentInstance;
if (currentInstance == other) {
sameReference = true;
return;
}
Class<T> currentInstanceClass = (Class<T>) currentInstance.getClass();
if (other == null || currentInstanceClass != other.getClass()) {
isEquals = false;
return;
}
this.other = (T) other;
}

@Override
protected boolean interruptEqualityCheck() {
return sameReference || super.interruptEqualityCheck();
}

public TypedEqualsBuilder<T> append(FailableFunction<T, ?, Exception> extractor) {
if (interruptEqualityCheck()) {
return this;
}
try {
super.append(extractor.apply(currentInstance), extractor.apply(other));
} catch (Exception e) {
throw new RuntimeException(e);
}
return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.lang3.builder;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class TypedEqualsBuilderTest {

@Test
void test_complete_equals() {
TestObject testObject1 = new TestObject(1, 2);
TestObject testObject2 = new TestObject(1, 3);
TestObject testObject3 = new TestObject(1, 2);

assertEquals(testObject1, testObject1);
assertNotEquals(testObject1, testObject2);
assertNotEquals(testObject2, testObject1);

assertTrue(
new TypedEqualsBuilder<>(testObject1, testObject2)
.append(TestObject::getA)
.isEquals());
assertTrue(
new TypedEqualsBuilder<>(testObject1, testObject3)
.append(TestObject::getA)
.append(TestObject::getB)
.isEquals());
assertFalse(
new TypedEqualsBuilder<>(testObject1, testObject2)
.append(TestObject::getA)
.append(TestObject::getB)
.isEquals());
assertFalse(
new TypedEqualsBuilder<>(testObject2, testObject1)
.append(TestObject::getA)
.append(TestObject::getB)
.isEquals());
assertFalse(
new TypedEqualsBuilder<>(testObject1, null)
.append(TestObject::getA)
.isEquals());
assertFalse(
new TypedEqualsBuilder<>(testObject1, "")
.append(TestObject::getA)
.isEquals());
assertThrows(RuntimeException.class,
() -> new TypedEqualsBuilder<>(testObject1, testObject2)
.append(TestObject::getSomethingWithException)
.isEquals());
}

private static class TestObject {
int a;
int b;

public TestObject(int a, int b) {
this.a = a;
this.b = b;
}

public int getA() {
return a;
}

public int getB() {
return b;
}

public int getSomethingWithException() throws Exception {
throw new Exception("something went wrong");
}

@Override
public boolean equals(Object obj) {
return new TypedEqualsBuilder<>(this, obj)
.append(TestObject::getA)
.append(TestObject::getB)
.isEquals();
}
}
}

0 comments on commit 602c964

Please sign in to comment.