Skip to content
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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing punctuation, sentence fragment

* The default value is {@code true}.
*/
private boolean isEquals = true;
protected boolean isEquals = true;
Copy link
Contributor

Choose a reason for hiding this comment

The 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;
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.
Copy link
Contributor

Choose a reason for hiding this comment

The 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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sentence fragment

*
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.
Copy link
Contributor

Choose a reason for hiding this comment

The 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&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 {
Copy link
Member

Choose a reason for hiding this comment

The 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 Type or Class apparently...

Copy link

Choose a reason for hiding this comment

The 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.

Copy link
Author

Choose a reason for hiding this comment

The 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.
So the Type is a Java Class.

Copy link
Member

Choose a reason for hiding this comment

The 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.

✅️ 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();
}
}
}
Loading