Lombok: Problem mit hashCode() auf Nullattribut bei Verwendung auf Hash-basierter Struktur

Erstellt am 19. Juli 2019  ·  3Kommentare  ·  Quelle: projectlombok/lombok

Die @EqualsAndHashCode -Anmerkung, die ein Long-Attribut wie pk verwendet, kann bei Verwendung mit Hash-basierten Strukturen (wie HashSet) zu einem unerwarteten Verhalten führen.

z.B.:

<strong i="9">@Entity</strong>
@EqualsAndHashCode(of = "pk")
class Foo {

    <strong i="10">@Id</strong>
    private Long pk;

    private LocalDate createdAt;

}
<strong i="13">@Entity</strong>
class Foo {

    <strong i="14">@Id</strong>
    private Long pk;

    private LocalDate createdAt;

    public int hashCode() {
        int PRIME = true;
        int result = 1;
        Object $pk = this.getPk();
        int result = result * 59 + ($pk == null ? 43 : $pk.hashCode());
        return result;
    }

    public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }
}

Wenn also die Instanz mit pk = null und andere mit pk = 43, gibt sie den gleichen Hash-Code zurück und kann auf der Hash-basierten Struktur als gleich angesehen werden, was sie nicht sind.

Und im Fall der Verwendung von OmniFaces ListConverter, die toString verwenden, haben wir das gleiche Problem.

Geben Sie möglicherweise eher einen Hashcode der Objektinstanz als eine fest codierte Konstante zurück

Haben Sie dieses Szenario bereits angenommen oder kennen Sie eine Möglichkeit, diese Situation zu umgehen?!

Versions Information

  • Lombok => 1.18.8
  • Plattform => Windows 10 JDK 11.0.4 IntelliJ

Hilfreichster Kommentar

43 ist wahrscheinlich so gut wie jede andere Zahl und besser als -1, 0 und 1. Wenn man sie konfigurierbar macht, erhöht sich der Wartungsaufwand für einen sehr geringen Mehrwert.

Die Verwendung des Identity-Hashcodes für null würde den Equals-Vertrag brechen.

Alle 3 Kommentare

Wenn also die Instanz mit pk = null und andere mit pk = 43, gibt sie denselben Hash-Code zurück

Das spielt keine Rolle. Außerdem wird es immer Hash-Kollisionen geben, egal, was Sie wählen.

Beachten Sie, dass Arrays.hashCode , String.hashCode und viele andere Tonnen von Kollisionen erzeugen, eher unnötig.

Geben Sie möglicherweise eher einen Hashcode der Objektinstanz als eine fest codierte Konstante zurück

In meinem manuell geschriebenen Code behaupte ich, dass er nicht aufgerufen wird, bevor ein id zugewiesen wird. Das ist sicherlich seltsam, aber alle Alternativen sind es auch.

Es wäre möglich, einen Anmerkungsparameter zu erstellen, der angibt, welcher Wert verwendet werden sollte, wenn der PK in diesem Fall null ist. Standardmäßig 43.

Dies würde dem Entwickler mehr Kontrolle geben.

@EqualsAndHashCode(of = "pk", ifAnyNull = -1)

Daher wird für jedes Feld, das null war, -1 anstelle von 43 verwendet

43 ist wahrscheinlich so gut wie jede andere Zahl und besser als -1, 0 und 1. Wenn man sie konfigurierbar macht, erhöht sich der Wartungsaufwand für einen sehr geringen Mehrwert.

Die Verwendung des Identity-Hashcodes für null würde den Equals-Vertrag brechen.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen