Lombok: Problema com hashCode() no atributo nulo quando usado em estrutura baseada em hash

Criado em 19 jul. 2019  ·  3Comentários  ·  Fonte: projectlombok/lombok

A anotação @EqualsAndHashCode que usa o atributo Long como pk pode causar algum comportamento inesperado quando usado com estrutura baseada em hash (como HashSet).

por exemplo.:

<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());
    }
}

Portanto, quando a instância com pk = null e outra com pk = 43, ela retornará o mesmo código hash e poderá ser considerada a mesma em estrutura baseada em hash, o que não é.

E no caso de usar o OmniFaces ListConverter que usa toString temos o mesmo problema.

Talvez retorne um hashcode da instância do objeto em vez de uma constante codificada

Você já pegou esse cenário, ou conhece alguma forma de contornar essa situação?!

Informação da versão

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

Comentários muito úteis

43 é provavelmente tão bom quanto qualquer outro número, e melhor que -1, 0 e 1. Torná-lo configurável adiciona carga de manutenção para um valor agregado muito baixo.

Usar o hashcode Identity para null quebraria o contrato de igualdade.

Todos 3 comentários

Então quando a instância com pk = null e outra com pk = 43, ela retornará o mesmo código hash

Isso não importa. Além disso, sempre haverá colisões de hash, não importa o que você escolher.

Observe que Arrays.hashCode , String.hashCode e muitos outros produzem toneladas de colisões, desnecessariamente.

Talvez retorne um hashcode da instância do objeto em vez de uma constante codificada

No meu código escrito manualmente, estou afirmando que ele não é chamado antes que um id seja atribuído. Isso é certamente estranho, mas todas as alternativas também são.

Seria possível criar um parâmetro de anotação que informasse qual valor deve ser usado quando o PK for nulo, neste caso. Por padrão 43.

Isso daria mais controle ao desenvolvedor.

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

Portanto, usará -1 em vez de 43, para qualquer campo que fosse nulo

43 é provavelmente tão bom quanto qualquer outro número, e melhor que -1, 0 e 1. Torná-lo configurável adiciona carga de manutenção para um valor agregado muito baixo.

Usar o hashcode Identity para null quebraria o contrato de igualdade.

Esta página foi útil?
0 / 5 - 0 avaliações