Problema com EntityManager e Generics

6 respostas
danieldestro

Problema muito estranho ocorrendo. Estou usando JPA como API de persistência e Java 5.

Tenho uma classe com um método de busca definido assim:

public <T extends BaseEntity> T find(Class<T> clazz, Serializable pk) { try { return em.find(clazz, pk); } catch (RuntimeException e) { throw new BaseException(e); } }

Porém o código acima não compila (ao menos no JDeveloper 10.1.3.2-4066). Ocorre a seguinte mensagem de erro:

Ele diz que não encontra o método find no EntityManager, porém, segundo a documentação da API ele é definido assim:

No entanto, se eu mudo de <T extends …> de BaseEntity para Object na assinatura do método, ele compila:

public &lt;T extends Object&gt; T find(Class&lt;T&gt; clazz, Serializable pk) { try { return em.find(clazz, pk); } catch (RuntimeException e) { throw new BaseException(e); } }

Não entendo porque funciona com Object e não funciona com a minha interface BaseEntity.

Porém, eu acabei mudando o código como abaixo e funciona:

public &lt;T extends BaseEntity&gt; T find(Class clazz, Serializable pk) { try { return (T) em.find(clazz, pk); } catch (RuntimeException e) { throw new BaseException(e); } }

Retirei o <T> do primeiro argumento e faço um cast do retorno do método em.find().

Alguém tem idéia do porquê???

6 Respostas

ddduran

Você já achou tudo.

o grande problema é que seu IDE lhe traiu com a mensagem de erro.
por exemplo fiz o mesmo código que você aqui e o erro que me traz é “can not convert T to T”

você tem que lembrar que quando rodar seus generics serão trocados por "Classes reais"
então vamos fazer o que você fez sem generics, ficaria assim

public BaseEntity  find(Class clazz, Serializable pk) {   
    try {   
        return em.find(clazz, pk);   // esse metodo retorna um Object logo precisa de um cast, afinal o mais generico aceita o mais
                                               // especifico, o contrario não
    } catch (RuntimeException e) {   
        throw new BaseException(e);   
    }   
}

então tudo que precisava era do Cast.

acho que o unico problema foi seu IDE que lhe pregou uma peça

danieldestro

Mesmo se eu fizer assim, não rola:

public &lt;T extends BaseEntity&gt; T find(Class clazz, Serializable pk) { try { return (T) em.find(clazz, pk); } catch (RuntimeException e) { throw new BaseException(e); } }

Acontece, que eu defino que T é subclasse de BaseEntity, logo, ele pode receber qualquer filho dela e retorná-lo.

Eu estou enganado?

ddduran

então aqui funcionou normalmente, só colocando o cast.

você está certo, deve aceitar qualquer filho de BaseEntity

você pode mandar a declaração da sua classe?

faz um teste, tenta compilar esse projeto com o bom e velho javac do console :smiley:
só para averiguar se é o IDE

danieldestro

javac? Muitas dependências de biblotecas… Deixa pra lá.
Talvez eu tente no Eclipse depois.

ddduran

danieldestro:
javac? Muitas dependências de biblotecas… Deixa pra lá.
Talvez eu tente no Eclipse depois.

hahaha meio chato mesmo eu nem lebro como usa direito (pobre escravo de IDE que sou)

mas eu fiz no eclipse mesmo

ddduran

mesmo assim manda a declaração da sua classe
e se testar no eclipse e funcar, avisa ae para eu nunca usar o JDeveloper

Criado 1 de novembro de 2007
Ultima resposta 1 de nov. de 2007
Respostas 6
Participantes 2