16 janeiro 2009

SCJP - 02 - Encapsulamento

Eu realmente pensava que o gerador de código do Eclipse era bacaninha... Mas de vez em quando ele faz umas coisas meio toscas, que dão trabalho pra gente descobrir depois :(

Dessa vez é rápido. Bem rápido. Digamos que você tem uma determinada classe persistente do Hibernate:

public class Pessoa {
 private Pessoa pai;
 private Pessoa mãe;
 private String nome;
 private Date nascimento;

 //Getters e Setters

}

Talvez, ao você mandar que a sua IDE implemente os demais métodos (gets, sets, equals e hashcode), você se depare com uma construção parecida no equals():

public boolean equals(Object obj) {
 if (this == obj)
     return true;
 if (! super.equals(obj))
     return false;
 if (! getClass().equals(obj.getClass()))
     return false;

 Pessoa other = (Pessoa) obj;

 ...

 if (pai == null) {
     if (other.pai != null)
         return false;
 } else if (pai.equals(other.pai))
     return false;

 ...
}


Suponha que a variável de instância pai seja mapeada como um relacionamento lazy-load, ou seja, carregado do banco somente quando explicitamente necessário. Agora imagine duas instâncias da classe Pessoa, que nós chamaremos de a e b. De maneira semelhante, imagine que ambas, a e b apontem como pai uma mesma instância da classe Pessoa, aqui chamada de c.

Em algum momento dentro do seu código fonte, você fez uma chamada ao método getPai() na instância a. Devido ao lazy-load, o hibernate se encarregaria de carregar este relacionamento para você. Mas o que ocorreria quando você realizasse um a.equals(b)? A variavel de instância a.pai já estaria carregada, e referenciando c, enquanto que b.pai ainda não estaria inicializada, referenciando null. E então, ao passar pelo trecho de código do método equals mostrado acima, o resultado do equals() seria false, apesar das linhas da tabela Pessoa, referentes às nossas instâncias a e b estarem referenciando o mesmo pai.

Isso tudo, porque durante a geração de código, sua IDE não realizou o encapsulamento das variáveis membro. É isso mesmo ou eu fiquei bêbado com 500 ml de suco de laranja hoje? Eu sempre achei que o equals() acima deveria, na verdade, ser o abaixo:


public boolean equals(Object obj) {
   if (this == obj)
      return true;
   if (! super.equals(obj))
      return false;
   if (! getClass().equals(obj.getClass()))
      return false;

   Pessoa other = (Pessoa) obj;

   ...

   if (getPai() == null) {
      if (other.getPai() != null)
         return false;
   } else if (getPai().equals(other.getPai()))
      return false;

   ...
}

Creative Commons License
Esta obra está licenciada sob uma Licença Creative Commons.
Comentários
0 Comentários

0 comments:

Postar um comentário

Regras são chatas, mas...

- Seu comentário precisa ter relação com o assunto do post;
- Em hipótese alguma faça propaganda de outros blogs ou sites;
- Não inclua links desnecessários no conteúdo do seu comentário;
- Se quiser deixar sua URL, comente usando a opção OpenID;
- CAIXA ALTA, miguxês ou erros de ortografia não serão tolerados;
- Ofensas pessoais, ameaças e xingamentos não são permitidos;