Composite Element Must Implement equals() and hashCode()

ID

java.hibernate_equals_in_composite_elements

Severity

high

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Reliability

Language

Java

Tags

best-practice, hibernate, orm, reliability

Description

Reports composite-element classes used with @ElementCollection that do not implement both equals(Object) and hashCode(). Hibernate relies on value equality for set semantics and dirty-checking in element collections. Without these methods, duplicates cannot be detected and changes may be lost.

Rationale

Element collections map value objects directly into a collection table. Hibernate compares old and new states using equals() to determine which rows to insert, update, or delete. When equals() and hashCode() are missing, Object identity comparison is used instead, causing Hibernate to delete and re-insert all rows on every flush.

// Bad: composite element without equals/hashCode
class Tag {
    private String name;
    private String value;
}

@Entity
class Product {
    @Id Long id;
    @ElementCollection
    Set<Tag> tags;
}

Remediation

Implement both equals(Object) and hashCode() in every class used as a composite element in an @ElementCollection:

// Good: composite element with proper equals/hashCode
class Tag {
    private String name;
    private String value;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Tag)) return false;
        Tag that = (Tag) o;
        return Objects.equals(name, that.name)
            && Objects.equals(value, that.value);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, value);
    }
}