Creio que a maioria dos desenvolvedores Java alguma vez se deparou com o trabalhoso problema de persistir informações em um banco de dados relacional. E muitos deles descobriram no Hibernate uma (relativamente) simples e eficiente solução.

Este framework de mapeamento objeto-relacional tornou-se o padrão de facto para realizar o gerenciamento de entidades persistentes em aplicações Java (depois do fiasco dos Entity Beans), tendo muitas de suas idéias adotadas na especificação da JPA. Além da facilidade de definição dos mapeamentos e de uma completa API para a realização de consultas, um dos seus pontos fortes é a ótima documentação disponível.

Entretanto, existem algumas funcionalidades para as quais esta documentação é quase inexistente. E dentre elas temos os esquecidos, mas bastante úteis, transformadores de resultados.

O problema!

Para entender a utilidade deste recurso, considere a seguinte consulta de alunos utilizando HQL (os detalhes podem ser abstraídos sem maiores problemas):

...
List resultado = session.createQuery("select matricula, nome, curso.nome from Aluno").list();
...

Com esta simples projeção restringimos a busca e aumentamos a performance da consulta de todos os alunos persistidos. Entretanto, teremos como resultado final uma lista de Object[] que precisaria ser manipulada para extrair os diversos campos.

Esta manipulação podería ser um laço para percorrer a lista resultante e, para cada array de objetos, instanciar DTOs ou entidades. Simples, mas nada divertido…

Ou então poderíamos criar um construtor para aluno que aceite os parâmetros da consulta e substituir a query por "select new Aluno(matricula, nome, curso.nome) from Aluno" . Dessa forma teríamos uma lista de alunos pronta, mas que necessitaria de novos construtores a cada novo parâmetro necessário.

Para resolver problemas deste tipo é que vamos em busca dos ResultTransformers.

A interface ResultTransformer

Escondida na API do Hibernate existe uma interface que possibilita transformar o resultado de uma consulta, seja ela com Criteria, HQL ou SQL (o suporte aos dois últimos foi adicionado na versão 3.2) que utilize projeções em uma representação mais prática do que, por exemplo, uma lista de Object[]. Apresento então a pequena ResultTransformer:

public interface ResultTransformer extends Serializable {
	public Object transformTuple(Object[] tuple, String[] aliases);
	public List transformList(List collection);
}

Os dois métodos especificados são aplicados em diferentes momentos para transformar o resultado de uma query: transformTuple é chamado durante o processamento inicial do resultado, com acesso às colunas retornadas pela consulta e aos aliases especificados para cada uma delas (se existirem); no caso de transformList a chamada é imediatamente antes do Hibernate retornar o resultado de uma consulta.

Alguns transformadores prontos para usar

Mas de que adianta uma interface sem implementações, não é? Felizmente o Hibernate disponibiliza algumas classes prontas para serem usadas em seus projetos.

Voltemos ao nosso problema: como não ter trabalho para manipular o resultado de consultas com projeção?

A primeira opção é o AliasToBeanResultTransformer. Este transformador mapeia aliases (se você não sabe que o são alias, aguarde mais um pouco para entender com o exemplo) de colunas em atributos de objetos pertencentes à classe definida em seu construtor, populando-os através de métodos setters (via setter injection). A utilização pode ser vista no exemplo abaixo:

...
List<AlunoDTO> alunos = session
    .createQuery( "select matricula as matricula, nome as nomeAluno, curso.nome as nomeCurso from Aluno" )
    .setResultTransformer(new AliasToBeanResultTransformer(AlunoDTO.class))
    .list();
...

Comparando com o código original vemos algumas diferenças. A primeira é a utilização da palavra-chave “as”. Esta é a forma de definir aliases (apelidos) para as colunas que serão utilizados para popular instâncias da classe AlunoDTO através de setters no estilo setNomeAluno() ou setNomeCurso().

A segunda diferença é a chamada ao método setResultTransformer() da interface Query. Com ela é possível determinar uma estratégia de transformação de resultados de acordo com a necessidade da consulta. Neste caso, informamos uma instância de AliasToBeanResultTransformer, definido para transformar as colunas em objetos do tipo AlunoDTO.

Como alternativa para a criação de DTOs ou de métodos setters em entidades podemos utilizar o AliasToEntityMapResultTransformer. Com ele a lista de tuplas será transformada em uma lista de mapas, onde cada cada um deles terá um conjunto de entradas alias => valor_da_coluna. Dessa forma temos uma representação mais fácil de ser manipulada do que a original.

Logo abaixo vê-se um exemplo de seu emprego:

...
List<Map<String,Object>> mapaAlunos= session
    .createQuery( "select matricula as matricula, nome as nomeAluno, curso.nome as nomeCurso from Aluno" )
    .setResultTransformer(new AliasToEntityMapResultTransformer())
    .list();
...

Viram como este recurso pode ser útil? Além destes dois apresentados existem mais transformadores que podem ser utilizados em outros casos, como o DistinctRootEntityResultTransformer, empregado para evitar duplicidade de entidades no resultado. E se ainda não for suficente, sempre é possível criar novas estratégias implementando a interface ResultTransformer.

Anúncios

A utilização dos componentes do RichFaces facilita bastante a incorporação de características de aplicações ricas a sistemas web que utilizam JavaServer Faces. A cada nova versão da biblioteca, mais e mais opções tornam-se disponíveis para incrementar sua aplicação e facilitar o desenvolvimento de interfaces mais complexas.

Entretanto, é bom lembrar que, por trás de todas estas maravilhas da praticidade moderna que o RichFaces oferece, ainda temos o bom e velho JavaScript por baixo dos panos. É esta incrível linguagem, que somente recentemente começou a ganhar o prestígio merecido, que move a maioria das funcionalidades mágicas dos componentes. Para tal, os desenvolvedores da biblioteca utilizaram-se de dois frameworks JavaScript bastante conhecidos: Prototype e Script.aculo.us (baseado no primeiro).

Estes dois já foram (e alguns ainda os consideram) os preferidos para auxiliar no desenvolvimento de soluções em JavaScript. Por causa disso vários outros projetos incorporaram estas bibliotecas para agregar comportamentos diversos a por exemplo: componentes JSF. E adivinha quem também fez essa escolha? o pessoal do RichFaces…

Muito bem, mas e o jQuery? Onde ele entra nessa história toda?

Acontece que o jQuery e seus diversos plugins estão cada vez mais na cabeça (e nos códigos) dos desenvolvedores web. Ele vai além do Prototype em vários aspectos: ganhou inúmeros admiradores e contribuidores, e é hoje uma opção mais conveniente para a adição de comportamentos à paginas web.

Resumindo então o cenário: temos os componentes prontos do RichFaces que encapsulam transparentemente códigos que utilizam Prototype e Script.aculo.us e, caso necessário, podemos adicionar outros comportamentos necessários com jQuery.

Qual o problema então?

O “problema” é que um importante método tanto do Prototype quanto do jQuery possuem nomes iguais!

A principal função do Prototype, e que é utilizada basicamente para reduzir o tamanho dos códigos de manipulação de elementos da árvore DOM, é a $(). Esta pequena função substitui o longo método original para a busca de elementos da página por seu id: document.getElementById().

No jQuery, a função $() é o grande coringa: serve para buscar elementos da página através de seletores CSS, para criar novos elementos para serem adicionados à página ou para definir funções que devem ser executadas assim que a árvore de elementos tiver sido carregada pelo navegador (depois providencio um post mais detalhado sobre esta função tão versátil).

Então não é possível usar as duas ao mesmo tempo? E já que RichFaces utiliza Prototype, não posso usar jQuery quando empregar seus componentes? Mas é claro que pode!!

É possível utilizar as funcionalidades das duas bibliotecas com uma pequena adaptação: definindo um nome alternativo para a função $()do jQuery e utilizando-a sem a preocupação com conflitos com o Prototype. Veja o código abaixo como esta alternativa pode ser utilizada:

var $j = jQuery.noConflict();

$j("div").hide();
$('rodape').show();

Neste exemplo, a função $j() irá funcionar com o comportamento desejado para o jQuery e a função $() funciona como a sua definição original do Prototype. Simples assim!

Agora você pode usufruir do melhor dos dois mundos: a praticidade dos componentes prontos e a flexibilidade de definir novos comportamentos ou utilizar os plugins prontos do jQuery.

Acho que para um primeiro post “de verdade” este até que ficou bem longo… A idéia parecia bem simples no começo, mas a necessidade da contextualização acrescentou algumas linhas a mais…

E no caso de alguma dúvida, o espaço para comentários está aí para ser utilizado! 🙂