JPA: anotações nos getters ou atributos?

A especificação da JPA permite que você utilize as anotações em uma Entity de duas formasou nos atributos, ou nos getters. Também diz que não devemos misturar isso, pois o comportamento resultante não é especificado. Na época em que a JPA estava em draft, havia até um atributo na anotação @Entity em que você explicitava onde iria usar as anotações.

Se temos essas duas opções, qual devemos usar? Usando o hibernate, há uma diferença fundamental entre as duas abordagens: quando e se o objeto será carregado.

Considere a seguinte classe, anotada pelos atributos:

@Entity
public class Funcionario {
  @Id
  @GeneratedValue
  private Long id;

  private String nome;

  // getters e setters
}

E agora um pequeno código para carregar, de maneira lazy, um Funcionario de id 1:

  Funcionario f = manager.getReference(Funcionario.class, 1l);
  System.out.println(f.getId());      
  System.out.println(f.getNome());

Com a propriedade show_sql valendo true, o código ao rodar produz:

--- query select executada ---
1
Paulo Silveira

Se em vez de anotarmos o atributo id com @Id e @GeneratedValue, anotarmos o método getId, obteríamos:

1
--- query select executada ---
Paulo Silveira

Em outras palavras, se no final você só usasse a chave primária (como poderia acontecer se a view fosse uma página web e caísse em uma condição particular), a query nem mesmo teria sido executada! Com a anotação diretamente no atributo, qualquer invocação de método em um objeto carregado mesmo com o getReference vai disparar a query.

É interessante sempre anotar os getters em vez dos atributos, mas vale reparar que na maioria absoluta dos casos isso não vai trazer benefícios. Até mesmo porque, em uma aplicação real, estaremos com o cache de segundo nível habilitado, tornando desnecessárias essas pequenas otimizações.

6 Comentários

  1. Guilherme Chapiewski 26/06/2007 at 04:11 #

    Caramba, que engraçado. Mas eu acho que é bem como você falou, é um detalhe muito pequeno para se preocupar. Eu prefiro as anotações nos atributos porque fica bem mais claro. As anotações nos getters ficam muito “espalhadas”.

    Mas ultimamente eu tenho me questionado se eu gosto ou não de anotações… Você acabou de me dar uma idéia para escrever um post no meu blog 🙂

  2. Alexandre F. da Silva [afsrj] 26/06/2007 at 19:16 #

    Legal isso, mas nunca (NUNCA MESMO!!!) pensei que isso fosse possível.
    Paulo, o cenário de exemplo que você citou com uma view web, não ficou muito claro.

  3. Fagner Moura 27/06/2007 at 11:48 #

    Na verdade anotando o método, o Persistence Provider vai buscar o valor diretamente no método getXX(), ignorando até o nome do atributo.

    Anotando o método e utilizando getReference ele faz:

    1. Dada essa classe, crie um cara desse, pegue o Id e verifique se ele está Managed neste PersistenceContext
    2. Execute a Query atrás desse cara e resgate os valores da esta ocorrência de Id no banco.

    Assumo que não entendi bem o exemplo, mas de qualquer forma..

    Ou seja, a diferença é que mapeando o método, ele já tem o Id (caso este esteja controlado pelo PersistenceContext) e a query é executada apenas para resgatar os valores para a tupla com este Id no banco.

    trace:
    1 // já tenho o Id comigo
    — query select executada — // pegue os valores do banco
    Paulo Silveira // plim!

  4. Paulo Silveira 27/06/2007 at 12:02 #

    Fagner, é esse o funcionamento, mas creio que não seja esse o motivo.

    Quando anotamos o método, ele realmente ignora o atributo. E é por esse motivo que ele pode fazer a leitura um pouco mais “lazy”: ele sabe se voce esta precisando de um atributo pois pode interceptar a chamada dos métodos (getters).

    Já no caso de anotar os atributos, ele não pode garantir isso! Podemos usar os atributos de diversas formas, pois ele pode ser protected, pode ter um método não-getter acessando-o, assim por diante!

    Seria legal testar esse exemplo com o toplink!

  5. Thiago 15/08/2015 at 00:42 #

    Então, já que a boa prática é criar getters and setters sob demanda, devo anotar então meus atributos? Ou a necessidade de gerar a anotação para o JPA nos métodos é a demanda que tenho para justificar a implementação dos getters?

Deixe uma resposta