Entity equals()/hashCode() References @Id Field

ID

java.hibernate_id_equals_hashcode

Severity

low

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Reliability

Language

Java

Tags

hibernate, orm, reliability

Description

Reports @Entity classes where equals() or hashCode() references the @Id field. The JPA identifier is null for transient (unsaved) entities and changes upon persist(), breaking the contract of equals/hashCode for hash-based collections.

Rationale

When an entity is added to a HashSet before being persisted, its @Id is null, yielding one hash code. After persist(), the @Id is assigned, changing the hash code. The entity can no longer be found in the set, causing silent data loss. The same problem occurs when detaching and re-attaching entities.

// Bad -- @Id used in equals/hashCode
@Entity
class User {
    @Id private Long id;

    @Override
    public boolean equals(Object o) {
        return Objects.equals(id, ((User) o).id);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}

Remediation

Use a stable, immutable business key (e.g., email, UUID, natural key) or rely on the default Object identity:

// Good -- business key
@Entity
class User {
    @Id private Long id;
    @Column(unique = true) private String email;

    @Override
    public boolean equals(Object o) {
        return Objects.equals(email, ((User) o).email);
    }

    @Override
    public int hashCode() {
        return Objects.hash(email);
    }
}