1

Given we have such class:

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class User {
    @Id
    private Long id;

    private String name;

    private Integer age;

    @Override
    public final boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof User user)) return false;

        return Objects.equals(id, user.id);
    }

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

When I test it via EqualsVerifier (https://jqno.nl/equalsverifier/) I get an error:

java.lang.AssertionError: EqualsVerifier found a problem in class com.example.model.User.
-> Significant fields: equals relies on id, but hashCode does not.
  com.example.model.User@e11ecfa has hashCode 236055802
  com.example.model.User@e11ecfa has hashCode 236055802

Why I getting this error while using constant in hashcode is a best practice according to:

  1. https://thorben-janssen.com/ultimate-guide-to-implementing-equals-and-hashcode-with-hibernate/
  2. https://vladmihalcea.com/how-to-implement-equals-and-hashcode-using-the-jpa-entity-identifier/

Yes, I can suppress this error by .suppress(Warning.STRICT_HASHCODE) option. But looks like this behaviour should be used by EqualsVerifier by default. Or maybe I'm wrong?

ColdDeath
  • 49
  • 6
  • Your hashcode implementation is quite unusual. It will yield the same value for all instances. While this is allowed, it is not recommended, because hashmaps will perform worse when your class is used as key type. – Hulk Feb 12 '23 at 13:25
  • Does this answer your question? [Best implementation for hashCode method for a collection](https://stackoverflow.com/questions/113511/best-implementation-for-hashcode-method-for-a-collection) – Hulk Feb 12 '23 at 13:29
  • [your implementation of #equals seems to be wrong](https://stackoverflow.com/a/74730796/3426309) – Andrey B. Panfilov Feb 12 '23 at 17:09
  • @Hulk, please take a look on this article https://thorben-janssen.com/ultimate-guide-to-implementing-equals-and-hashcode-with-hibernate/ here is described why I use this variant of hashcode. The main point that it's JPA Entity and when the same classes have the same hashcode then they simply will be in one bucket but in meanwhile comparison will be provided by equals. And one more thing if hashcodes of two entities are the same it doesn't mean that entities are equal. But if xEntity.equals(yEntity) = true it does mean that entities are equal and their hashcodes too. – ColdDeath Feb 12 '23 at 21:09

1 Answers1

2

Disclaimer: I'm the creator and maintainer of EqualsVerifier.

You have to .suppress(Warning.STRICT_HASHCODE) in this case, because EqualsVerifier doesn't recognise this by default.

I'm aware of the best practices you cite, and I've considered enforcing them in EqualsVerifier, but I decided against it for now.

jqno
  • 15,133
  • 7
  • 57
  • 84
  • thank you for your answer! And some another question: what do you think of using if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) return false; instead of if (!(o instanceof User user)) return false; ? why EqualsVerifier doesn't allow such variant? – ColdDeath Feb 12 '23 at 21:18
  • I'm not familiar with that idiom, but it looks like you'd have to use `.usingGetClass()` to make it work. – jqno Feb 13 '23 at 06:52