Este ano acabei participando de projetos com duas excelentes equipes e tive muitas oportunidades de discutir arquitetura com elas, além de revisar código. Uma coisa que me surpreendeu foi como dois recursos do JPA, que fazem muita diferença, ainda estão pouco difundidos.
O primeiro é o uso de TypedQuery , introduzida a partir do JPA 2. O uso, para quem está acostumado com Query
, é bem simples:
TypedQuery<Entidade> query = em.createNamedQuery("Entidade.minhaQuery", Entidade.class); List<Entidade> resultados = query.getResultList();
Conforme o exemplo acima, os métodos que criam uma instância de Query
no EntityManager
também possuem outra versão sobrecarregada que recebe o tipo a ser retornado e criam uma TypedQuery
. Essa interface estende Query
fazendo com que todos os retornos que antes eram Object
passem a ser fortemente tipados, evitando casts e o uso do famigerado @SuppressWarnings("unchecked")
.
Além disso, os métodos de EntityManager
que instanciam TypedQuery
verificam, no momento da criação, se o retorno realmente pode ser atribuído para o tipo desejado, lançando uma exceção se não for o caso. Assim, temos erros fail-fast, ou seja, ao invés de descobrirmos no acesso a List
retornada que houve um erro de tipagem, temos uma exceção lançada exatamente na linha em que se originou o problema, facilitando sua correção.
Uma limitação de TypedQuery
é que ela só pode ser criada para queries que retornem exatamente um elemento no select. Os casos em que se faz projection, com Object[]
, não poderiam se beneficiar do recurso. Não poderiam porque há outro recurso não tão conhecido em JPA, mas poderoso, que é o SELECT NEW
:
SELECT NEW br.com.michaelnascimento.exemplo.ClasseArbitraria(e.umaPropriedade, e.outraPropriedade) FROM Entidade e
A query JPA acima retorna uma instância de ClasseArbitraria
, chamando o construtor que receberá as propriedades como parâmetros uma vez por “linha” retornada. Precisa-se usar o FQN (fully-qualified name, ou em termos práticos, pacote + nome) da classe pois ela não precisa estar alistada na persistence unit.
Uma das grandes vantagens do uso de SELECT NEW
não é só permitir o uso de TypedQuery
com projections, mas também evitar ainda mais casts nessa situação, além de permitir o uso de boas práticas de OO nesses cenários. Eu normalmente uso inner classes das entidades ou classes do mesmo pacote nestes cenários, às vezes até mesmo implementando uma interface comum com as minhas entidades. Assim, posso manter o encapsulamento, tanto por invocar métodos não-públicos da outer class quanto por permitir que outras classes de negócio trabalhem de forma transparente tanto com a entidade como com a minha abstração da projection – a que costumo me referir como view nos projetos.
Espero ajudar a difundir o uso dessas técnicas úteis no Brasil. E você, já as conhecia?
PS: Eu achei que ia fazer pelo menos um post a cada quinze dias, tsc, tsc :-/
muito bom o post! apabens.
isso ai cara! muito bom
nunca havia tido a sacada de usar os dois junto!
Parabéns.