-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add TypedEqualsBuilder class and test #1114
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. private please. Use getters/setters if needed |
||
|
||
private boolean testTransients; | ||
private boolean testRecursive; | ||
|
@@ -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. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. third person, or second person if you must. Tech docs should never be second person plural |
||
* | ||
* @return true if the equality is false | ||
*/ | ||
protected boolean interruptEqualityCheck() { | ||
return !isEquals; | ||
} | ||
|
||
/** | ||
* Tests if two {@code objects} by using reflection. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sentence fragment |
||
* | ||
|
@@ -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) { | ||
|
@@ -583,7 +592,7 @@ private void reflectionAppend( | |
* @since 2.0 | ||
*/ | ||
public EqualsBuilder appendSuper(final boolean superEquals) { | ||
if (!isEquals) { | ||
if (interruptEqualityCheck()) { | ||
return this; | ||
} | ||
isEquals = superEquals; | ||
|
@@ -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) { | ||
|
@@ -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; | ||
|
@@ -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; | ||
|
@@ -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; | ||
|
@@ -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; | ||
|
@@ -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; | ||
|
@@ -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)); | ||
|
@@ -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)); | ||
|
@@ -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; | ||
|
@@ -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) { | ||
|
@@ -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) { | ||
|
@@ -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) { | ||
|
@@ -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) { | ||
|
@@ -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) { | ||
|
@@ -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) { | ||
|
@@ -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) { | ||
|
@@ -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) { | ||
|
@@ -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) { | ||
|
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. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Needs a rewrite |
||
* 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<>(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 { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a confusing class name IMO. What is and where is the Type? It's not a Java There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is the class type. its refering to the T class parameter which is supported by this Builder subtype. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This equals builder is typed. We provide a type and then the field functions to build the equals method. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
✅️ Thanks for pointing that out! 👍 |
||
|
||
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(); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing punctuation, sentence fragment