JPA: Query genérica (pra não usar @SuppressWarnings a toda hora...)

6 respostas
goofed

Ae pessoal, estou começando com JPA e já senti um problema quanto a usar fazer selects usando queries e namedqueries…
Um exemplo:

Query query = entityManager.createNamedQuery("ProcuraPorNome");
List listaAutor = query.setParameter("nome", "Rachel de Queiroz").getResultList();

Nesse código eu teria que usar o List sem genérico o que gera um warning e assim teria que colocar um @SuppressWarnings(“unchecked”) da vida…
Mas isso seria só aqui… imagine em várias de minhas classes esses supress… eu odiaria isso. Fora que isso poderia encobrir um outro warning gerado desnecessariamente…

Eu procurei por soluções na net falando de DAO generico… mas por enquanto meu problema eh so com essa interface Query…
Eu criei uma classe QueryGenerico implements Query pra resolver o meu problema. Pra usar eu faço assim:

Query query = ... pego a query não generica
QueryGenerica<ContaCorrente> queryG = new QueryGenerica<ContaCorrente>(query); // passando a query nao generica no construtor.

E então todos os @SupressWarnings que deveria ter em milhares de classes se resumem à 2 miseros @SuppressWarnings que ficam na classe QueryGenerica. É claro que se o programador for jumento ele pode definir um tipo T que não vai ser o retorno esperado…

Então eu queria saber de vocês se alguem ja fez isso, e se isso não é nenhum pouco recomendado e se tem alguma outra maneira de resolver isso sem ter mto trabalho.

Vlw!
Aqui embaixo tem o codigo de uma aplicação rodando sem warnings…

Aqui vai o codigo da classe QueryGenerica:

package com.livraria.jpa;
public class QueryGeneric<T> implements Query {

	private Query query;

	public QueryGeneric(Query query) {
		this.query = query;
	}

	@Override
	public int executeUpdate() {
		return query.executeUpdate();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<T> getResultList() {
		return (List<T>)query.getResultList();
	}

	@SuppressWarnings("unchecked")
	@Override
	public T getSingleResult() {
		return (T)query.getSingleResult();
	}

	@Override
	public QueryGeneric<T> setFirstResult(int startPosition) {
		return new QueryGeneric<T>(query.setFirstResult(startPosition));
	}

	@Override
	public QueryGeneric<T> setFlushMode(FlushModeType flushMode) {
		return new QueryGeneric<T>(query.setFlushMode(flushMode));
	}

	@Override
	public QueryGeneric<T> setHint(String hintName, Object value) {
		return new QueryGeneric<T>(query.setHint(hintName, value));
	}

	@Override
	public QueryGeneric<T> setMaxResults(int maxResult) {
		return new QueryGeneric<T>(query.setMaxResults(maxResult));
	}

	@Override
	public QueryGeneric<T> setParameter(String name, Object value) {
		return new QueryGeneric<T>(query.setParameter(name, value));
	}

	@Override
	public QueryGeneric<T> setParameter(int position, Object value) {
		return new QueryGeneric<T>(query.setParameter(position, value));
	}

	@Override
	public QueryGeneric<T> setParameter(String name, Date value,
			TemporalType temporalType) {
		return new QueryGeneric<T>(query.setParameter(name, value, temporalType));
	}

	@Override
	public QueryGeneric<T> setParameter(String name, Calendar value,
			TemporalType temporalType) {
		return new QueryGeneric<T>(query.setParameter(name, value, temporalType));
	}

	@Override
	public QueryGeneric<T> setParameter(int position, Date value,
			TemporalType temporalType) {
		return new QueryGeneric<T>(query.setParameter(position, value, temporalType));
	}

	@Override
	public QueryGeneric<T> setParameter(int position, Calendar value,
			TemporalType temporalType) {
		return new QueryGeneric<T>(query.setParameter(position, value, temporalType));
	}
}

E aqui um codigo de exemplo usando esse novo “artificio”:
*A classe Autor é um POJO/Entidade com uma NamedQuery pra procurar por nome…

public class Teste {

	public static void main(String[] args) {
		EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("Livraria");
		EntityManager entityManager = entityManagerFactory.createEntityManager();
			
		List<Autor> lista;
		QueryGeneric<Autor> queryGeneric;
		Query query;
		
		query = entityManager.createNamedQuery(Autor.NamedQueries.ProcuraPorNome.toString());
		queryGeneric = new QueryGeneric<Autor>(query);
		
		lista = queryGeneric.setParameter("nome", "Rachel de Queiroz").getResultList();
		
		for (Autor autor : lista)
			System.out.println(autor.toString());	
			
		entityManager.close();
		entityManagerFactory.close();
	}

}

6 Respostas

T

Está quase OK. Uma coisa que ajudaria um pouco é você poder passar um parâmetro Class, de modo que a classe possa checar o cast. Outra é que em inglês o adjetivo vem antes do substantivo (GenericQuery, não QueryGeneric). Não tenho como testar se estou certo, mas vou postar minhas modificações.

package com.livraria.jpa;
public class GenericQuery&lt;T&gt; implements Query {

	private Query query;
    
    private Class&lt;T&gt; klass;

	public GenericQuery(Class&lt;T&gt; klass, Query query) {
        this.klass = klass;
		this.query = query;
	}

    // Método "factory" - pode ser usado em vez de "new GenericQuery" e economiza
    // uma menção ao tipo (em vez de new GenericQuery&lt;X&gt;(X.class,...) você especifica
    // GenericQuery.adaptQuery(X.class,...).
    public static &lt;T&gt; GenericQuery&lt;T&gt; adaptQuery (Class&lt;T&gt; klass, Query query) {
        return new GenericQuery&lt;T&gt; (klass, query);
    }
    
	@Override
	public int executeUpdate() {
		return query.executeUpdate();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List&lt;T&gt; getResultList() {
        // Isto promete que esta lista conterá apenas elementos do tipo "T".
		return Collections.checkedList (query.getResultList(), klass);
	}

	@SuppressWarnings("unchecked")
	@Override
	public T getSingleResult() {
        // isto força o "class cast exception" a ocorrer aqui dentro 
		return klass.cast (query.getSingleResult());
	}

	@Override
	public GenericQuery&lt;T&gt; setFirstResult(int startPosition) {
		return new GenericQuery&lt;T&gt;(klass, query.setFirstResult(startPosition));
	}

	@Override
	public GenericQuery&lt;T&gt; setFlushMode(FlushModeType flushMode) {
		return new GenericQuery&lt;T&gt;(klass, query.setFlushMode(flushMode));
	}

	@Override
	public GenericQuery&lt;T&gt; setHint(String hintName, Object value) {
		return new GenericQuery&lt;T&gt;(klass, query.setHint(hintName, value));
	}

	@Override
	public GenericQuery&lt;T&gt; setMaxResults(int maxResult) {
		return new GenericQuery&lt;T&gt;(klass, query.setMaxResults(maxResult));
	}

	@Override
	public GenericQuery&lt;T&gt; setParameter(String name, Object value) {
		return new GenericQuery&lt;T&gt;(klass, query.setParameter(name, value));
	}

	@Override
	public GenericQuery&lt;T&gt; setParameter(int position, Object value) {
		return new GenericQuery&lt;T&gt;(klass, query.setParameter(position, value));
	}

	@Override
	public GenericQuery&lt;T&gt; setParameter(String name, Date value,
			TemporalType temporalType) {
		return new GenericQuery&lt;T&gt;(klass, query.setParameter(name, value, temporalType));
	}

	@Override
	public GenericQuery&lt;T&gt; setParameter(String name, Calendar value,
			TemporalType temporalType) {
		return new GenericQuery&lt;T&gt;(klass, query.setParameter(name, value, temporalType));
	}

	@Override
	public GenericQuery&lt;T&gt; setParameter(int position, Date value,
			TemporalType temporalType) {
		return new GenericQuery&lt;T&gt;(klass, query.setParameter(position, value, temporalType));
	}

	@Override
	public GenericQuery&lt;T&gt; setParameter(int position, Calendar value,
			TemporalType temporalType) {
		return new GenericQuery&lt;T&gt;(klass, query.setParameter(position, value, temporalType));
	}
}
public class Teste {

	public static void main(String[] args) {
		EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("Livraria");
		EntityManager entityManager = entityManagerFactory.createEntityManager();
			
		GenericQuery&lt;Autor&gt; qryProcuraPorNome = new GenericQuery(Autor.class, 
            entityManager.createNamedQuery(Autor.NamedQueries.ProcuraPorNome.toString()));
		List&lt;Autor&gt; autores = qryProcuraPorNome.setParameter("nome", "Rachel de Queiroz").getResultList();
		
		for (Autor autor : autores)
			System.out.println(autor.toString());	
    
        // Usando um método "factory"
        GenericQuery&lt;Titulo&gt; qryProcuraPorTitulo = GenericQuery.adaptQuery (Titulo.class,
            entityManager.createNamedQuery(Autor.NamedQueries.ProcuraPorNome.toString()));
        
        for (Titulo titulo : qryProcuraPorTitulo.setParameter ("titulo", "O Quinze").getResultList()) {
            System.out.println (titulo);
        }
			
		entityManager.close();
		entityManagerFactory.close();
	}

}
goofed

Nossa kra… Tu eh tipo o mestre hein… hehehe. Pensou em tudo ae.
O lance do QueryGeneric so botei pra ficar mais facil de ler… Q com Q… hehhe

Agora so me resta uma pergunta: Isso que to fazendo eh válido? Alguem pode me crucificar por isso? Me denominar um POGer?

Vlwzão!

T

Muito pelo contrário, acho que é uma forma de suprir uma deficiência da JPA, que não usa todos os recursos do Java 5 - só annotations.

goofed

Ops… surgiu mais uma duvida… :smiley: Mas diz respeito a Genericos:
Se eu defino uma classe “class Classe { }” não existe uma forma de fazer um… T.class?
Vlw!

T

A resposta é “não”, por isso é que eu tive de passar explicitamente o Autor.class ou Titulo.class como parâmetro.

goofed

É neh… era so uma questao de diminuir mesmo… Continua useful…

Vlw mesmo pela ajuda e atenção! Tu é gente fina!

Criado 8 de janeiro de 2008
Ultima resposta 8 de jan. de 2008
Respostas 6
Participantes 2