Reputation: 285
I recently stumbled across Lombok
and wanted to test it, when I ran into this slight problem.
Suppose I have
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Name extends AbstractName {
@NonNull
private String firstname;
@NonNull
private String lastname;
}
where AbstractName
is an empty abstract class. I want to test the equals
method with
@Test
public void testEquals() {
Name instance1 = new Name("Vorname","Nachname");
Name instance2 = new Name("Vorname","Nachname");
boolean expResult = true;
boolean result = instance1.equals(instance2);
assertEquals(expResult, result);
}
As you can see, I would expect the two instances of Name
to be equal. In case you add
System.out.println(instance1.getFirstname().equals(instance2.getFirstname()));
System.out.println(instance1.getLastname().equals(instance2.getLastname()));
one gets
true
true
So, why does the test fail? Is it a hashCode()
problem due to the inheritence of AbstractName
? How can I fix that?
BTW, it does not fail, if Name
is a standalone class and not a subclass of AbstractName
.
This is code created by Lombok
@java.lang.Override
@java.lang.SuppressWarnings("all")
@lombok.Generated
public boolean equals(final java.lang.Object o) {
if (o == this) return true;
if (!(o instanceof Name)) return false;
final Name other = (Name) o;
if (!other.canEqual((java.lang.Object) this)) return false;
if (!super.equals(o)) return false;
final java.lang.Object this$firstname = this.getFirstname();
final java.lang.Object other$firstname = other.getFirstname();
if (this$firstname == null ? other$firstname != null : !this$firstname.equals(other$firstname)) return false;
final java.lang.Object this$lastname = this.getLastname();
final java.lang.Object other$lastname = other.getLastname();
if (this$lastname == null ? other$lastname != null : !this$lastname.equals(other$lastname)) return false;
return true;
}
Upvotes: 1
Views: 2052
Reputation: 2931
So, why does the test fail? Is it a hashCode() problem due to the inheritence of AbstractName? How can I fix that? BTW, it does not fail, if Name is a standalone class and not a subclass of AbstractName
Elaborating regarding why the test would fail when callSuper is True.
Lets say you have a Child class which extends an abstract class. (or any other class for that matter)
Name.java:
@EqualsAndHashCode(callSuper = true)
public class Name extends AbstractName {
AbstractName.java:
public class AbstractName {
//some fields
Now, when we compare 2 instances of Name.java with same values then because we are overriding equals() and hashcode() methods using @EqualsAndHashCode
lombok annotation in Name.java so the values are checked correctly. But since we are not overriding the equals() and hashcode() method in AbstractName.java so by default the equals() will always fail even if the values of properties are the same (unless the AbstractName's object instances are pointing to same object reference)
So, one option would be to make @EqualsAndHashCode(callSuper = false)
in the Child class. But then the fields in the parent class (AbstractName.java) will not be compared
Solution:- Better option would be to add @EqualsAndHashCode(callSuper = true)
in Name.java and @EqualsAndHashCode
in AbstractName.java so that the equals() and hashcode() are overridden in both parent and child class so that the fields in all classes are compared correctly
Upvotes: 0
Reputation: 2801
Using @Data is a short cut which includes @EqualsAndHashCode. Try explicitly adding @EqualsAndHashCode and set callSuper
to false.
However, for long-term maintenance, it may be safer to override equals/hashCode in the base class and just return true/0, or apply @EqualsAndHashCode to the base class.
Upvotes: 3