Error message JPA Entity: direct reference to field xxx used in equals instead of getter getXXX

97 views
Skip to first unread message

john.c...@gmail.com

unread,
Dec 7, 2022, 9:21:13 PM12/7/22
to equalsverifier
Hello,
In equalsVerifier 3.12.1 I ran into this new error
JPA Entity: direct reference to field xxx used in equals instead of getter getXXX

I have been unable to resolve it when the field is inherited from a parent class and the parent class equals and hashcode method use the getter.  Below is a trivial example.  Am I missing something?

Example:

@Entity
class Parent {
   @Column(name = "text_content")
   @Basic(fetch = FetchType.LAZY)
    private String textContent;

    public void setTextContent(String textContent) {
        this.textContent = textContent
   }
   public String getTextContent() {
        return this.textContent;
    }

    public int hashCode() {
        return Objects.hash(getTextContent());
    }

    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null || getClass() != obj.getClass()) {
            return false;
        }
        Parent other = (Parent) obj;
        return Objects.equals(getTextContent(), other.getTextContent());
    }
}

@Entity
class Child extends Parent {

   @Column(name = "child_content")
   @Basic(fetch = FetchType.LAZY)
    private String childContent;

   public void setChildContent(String childContent) {
        this.childContent = childContent
   }
   public String getChildContent() {
        return this.childContent;
    }

    public int hashCode() {
        return Objects.hash(super.hashCode(), getChildContent());
    }

    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null || getClass() != obj.getClass()) {
            return false;
        }
        if(!super.equals(obj)) {
            return false'
        }
        Child other = (Child) obj;
        return Objects.equals(getChildContent(), other.getChildContent());
    }
}

class ChildTest {
    @Test
    public void testEqualsAndHashcode() {
        EqualsVerifier.forClass(Child.class).usingGetClass().suppress(Warning.NONFINAL_FIELDS).verify();
    }
}

John Camerin

unread,
Dec 12, 2022, 5:03:10 PM12/12/22
to equalsv...@googlegroups.com
I've done some code mining and this appears to me to be a bug in this new validation in EqualsVerifier.  The EqualsVerifier code is getting ALL of the fields of a class, regardless of whether those fields are declared in a superclass.  The method ClassAccessor.declaresMethod is asking the Class under test for the declaredMethod by name and parameter types. When asking a class in Java for the DeclaredMethods via reflection, the class will only return methods declared in that class and none of the methods in any parent class.  This method is not finding the getter since that method is declared in the parent class, thus causing the error.
In summary, there is a mismatch in the EqualsVerifier code WRT to fields being checked in the class hierarchy depth.  The fields check are every field from all superclasses, whereas the methods are only of the subclass under test.  These validations need to be aligned within EqualsVerifier in order for this Entity Lazy field check to be valid.

--
You received this message because you are subscribed to a topic in the Google Groups "equalsverifier" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/equalsverifier/QB4FNIV2_HA/unsubscribe.
To unsubscribe from this group and all its topics, send an email to equalsverifie...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/equalsverifier/4749a8c1-9b68-4ce2-9da6-d7a42dc226een%40googlegroups.com.

Dominik Hons

unread,
Dec 29, 2022, 4:43:11 AM12/29/22
to equalsverifier
I've come across this error with a very simple case. I have an entity with a LAZY reference to another entity. However, this reference is not used in the equals method. Removing FetchType.LAZY makes the test work, but it is not what I want.

@Getter
@Setter
@Entity
public class Foo {

@Id
private Long id;

@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "BAR_ID")
private Bar bar;

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Foo other)) {
return false;
}
return id != null && id.equals(other.id);
}

@Override
public int hashCode() {
return getClass().hashCode();
}

}


Dne pondělí 12. prosince 2022 v 23:03:10 UTC+1 uživatel john.c...@gmail.com napsal:
Reply all
Reply to author
Forward
0 new messages