getClass() equals getClass() ist sehr gefährlich, wenn man Hibernate nutzt.

Tja...und wieder in eine Falle getappt mit der man nicht wirklich rechnet. Beispielhaft hat mir Netbeans für die Klasse User folgende equals-Methode generiert:

@Override
public boolean equals(Object obj) {
    if (obj == null) {
        return false;
    }
    if (!(obj.getClass() == this.getClass())) {
        return false;
    }
    final User other = (User) obj;
    if ((this.username == null) ? (other.username != null) : !this.username.equals(other.username)) {
        return false;
    }
    return true;
}

Im Einsatz von Hibernate ist die equals-Methode im getClass-Vergleich mit false verlassen worden. Aber warum?

Hibernate Proxy

Hibernate setzt das Entwurfsmuster Proxy (oder Stellvertreter) ein um lazy loading zu ermöglichen. Lazy loading ist ein Konzept um Ressourcen zu sparen, bei dem Daten erst dann aus der Datenbank geladen, wenn sie auch tatsächlich gebraucht werden.

Auf das obere Codebeispiel bezogen bedeutet es, dass das Objekt obj nicht unbedingt eine Instanz der Klasse User sein muss. In meinem Fall lautete der Klassenname User_$$_javassist_2. Und daher lieferte der Vergleich der beiden Klassen false.

Lösung

Ein Artikel auf velacon.de geht auf dieses Problem noch konkreter ein und bietet eine interessante Lösung. Da ich in meinen Entitäten allerdings keine Abhängigkeit zu Hibernate erzeugen wollte, habe ich mich für die instanceOf Variante entschieden.

@Override
public boolean equals(Object obj) {
    if (obj == null) {
        return false;
    }
    if (!(obj instanceof User)) {
        return false;
    }
    final User other = (User) obj;
    if ((this.getUsername() == null) ? (other.getUsername() != null) : !this.getUsername().equals(other.getUsername())) {
        return false;
    }
    return true;
}

Zu beachten ist hierbei weiterhin, dass man auf Grund des angesprochenen Lazy loadings nicht direkt auf die Attribute zugreifen sollte, sondern immer an Hand deren Get-Methoden.

blogroll
tags