I need to compare two objects of the same class excluding some fields.
public final class Class1 {
private String a;
private String b;
private String c;
:
:
:
private String z;
private Date createdAt;
private Date updatedAt;
}
How can i find if the two objects of the above class are equal excluding createdAt and updatedAt values? Since there are a lot of fields in this class, i don't want to compare each of them one by one.
Please don't give AssertJ's recursive comparison solution as I don't need it for UnitTests.
Thank you in Advance!
CodePudding user response:
If overriding Object::equals
and Object::hashCode
is not an option, we can use the Comparator
API to construct a corresponding comparator:
final Comparator<Class1> comp = Comparator.comparing(Class1::getA)
.thenComparing(Class1::getB)
.thenComparing(Class1::getC)
.
.
.
.thenComparing(Class1::getZ);
Unfortunately, there is no way to do this without comparing all fields that should be equal.
CodePudding user response:
Try overriding equals method like below :
import java.util.Date;
import java.util.Objects;
public final class Class1 {
private String a;
private String b;
private String c;
private String z;
private Date createdAt;
private Date updatedAt;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Class1 class1 = (Class1) o;
return Objects.equals(a, class1.a) && Objects.equals(b, class1.b) && Objects.equals(c, class1.c) && Objects.equals(z, class1.z);
}
@Override
public int hashCode() {
return Objects.hash(a, b, c, z);
}
}
CodePudding user response:
I addition to the Comparator and hashCode()
/equals
method, you could also use Reflections.
- Create an annotation to exclude certain fields:
Blacklisting Example:
@Retention(RetentionPolicy.RUNTIME) //
@Target(ElementType.FIELD) //on class level
public @interface IngoreForEqualCheck { /* tagging only */ }
Use Reflection to analyze the objects you want to compare, by using
pClass.getFields()
and/orpClass.getDeclaredFields()
on the objects' class. This may be even different classes.Iterate over all fields that are NOT tagged to be ignored, compare values.
Optimizations
To extend on the blacklisting from above, also introduce whitelisting: also create an annotation
UseForEqualCheck
to only check those fields.For improved speed, when analyzing the respective class and its fields, you can create iterable lists of the fields to check, and instead of doing the Reflection fields analysis each time, simply use the lists.
Normally you would use
equals()
on the detected field values. You could also a) tag the class with another custom annotation, or b) check the fields for any whitelisting/blacklisting annotations, so that you will reliably use your new method for embedded/inherited/delegated annotated classes.
Warning
As with all reflections, you might get into trouble when analyzing hierarchies of classes, that have been modified during the compile process (javac) by annotation preprocessors, or by bytecode weaving. This mostly refers to Java EE aka Jakarta, but can happen anywhere where behind-the-scenes functionality is incorporated in your code, or runtime behavior is changed, like with injections, aspect oriented libraries etc.
CodePudding user response:
The quickest way without writing any code is Lombok
Lombok is one of the most used libraries in java and it takes a lot of Boilerplate code off your projects. If you need to read more on what it can and does, go here.
The way to implement what you need is pretty straightforward:
// Generate the equals and HashCode functions and Include only the fields that I annotate with Include
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@Getter // Generate getters for each field
@Setter // Generate setters for each field
public class Class1
{
@EqualsAndHashCode.Include // Include this field
private Long identity;
private String testStr1; // This field is not annotated with Include so it will not be included in the functions.
// ... any other fields
}
Lombok can do a lot more than this. For more information on @EqualsAndHashCode
refer to this.
You can always use @EqualsAndHashCode.Exclude
for a quicker solution to your use case:
@EqualsAndHashCode
@Getter // Generate getters for each field
@Setter // Generate setters for each field
public final class Class1 {
private String a;
private String b;
private String c;
:
:
:
private String z;
@EqualsAndHashCode.Exclude
private Date createdAt;
@EqualsAndHashCode.Exclude
private Date updatedAt;
}