Boa tarde, pessoal,
Estou com um problema que acredito que vocês já devem ter passado. Preciso de um método que descubro o tipo do passado por generics em tempo de execução. Para tal, 99% das respostas encontradas na interface, recaem sobre a mesma linha de código.
Dado uma classe A, para obter o tipo “B”, devemos fazer?
public class A<B>{
Class objectClass;
public void setObjectClass()
{
ParameterizedType tipo = (ParameterizedType)this.getClass().getGenericSuperclass();
objectClass = (Class)tipo.getActualTypeArguments()[0];
//aqui coloquei essa linha para ver o resultado apenas
System.out.println(objectClass.toString());
}
}
PS: se tiver erro de digitação ignorem pois eu escrevi o código não copiei e colei pois o original é bem maior
Bom, o código já dá erro na primeira linha. java.lang.ClassCastException: java.lang.Class . Claro, o método “getGenericSuperclass()” retorna um objeto do tipo class e estou fazer um cast para ParameterizedType que está dando pau.
Mas todo lugar que vou, passam essa solução e simplesmente não funciona aqui. Já passei para uns três amigos aqui no trabalho e ninguem descobre. Alguém aqui, tem idéia do que acontece? Estou pensando em abortar a idéia de usar Generics nos meus projetos pois estou com receio de mais erros estranhos.
Antes que alguém sugira, tambem já fiz esse teste: Criar uma subclasse e partir chamar a generica. Ficou algo assim:
public class TesteDAO()
{
public TesteDAO(){
new A();
//Bean sendo um bean válido qualquer
}
}
O resultado desejado é que objectClass, seja um object Class do tipo Bean e com isso eu possa fazer um “.getSimpleName” e ele me retorne a String “Bean”.
Espero ter conseguido expressar meu problema e que alguém possa me ajudar. USo JDK 5.0 aqui no trabalho. Mas se o problema for versão em casa tenho o 6.0 (mas não fiz todos os testes que já fiz aqui).
Agradeço qualquer ajuda.
O problema de Generics em Java é o conceito de “erasure”.
Basicamente, a menos que você guarde em um objeto da classe A uma referência para a classe B (ou seja, B.class), você não tem como saber B.
Não deixe de usar Generics nos seus projetos; é só saber como você deve proceder.
Vou dar um exemplo daqui a pouco.
Vc pode fazer assim
public class A<B>{
Class<B> objectClass;
}
// --------
public class TesteDAO<B>()
{
public TesteDAO(){
A<B> objectAofB = new A<B>();
}
Note que em momento algum vc precisa saber quem é B.
Eu preciso recuperar o nome do tipo passado ao genérico como String. Pode ser que exista até forma mais “elegante” de se fazer, mas gostaria de saber se isso for possível.
Em um último caso, farei com que a string vire um parametro dos métodos, vai funcionar, mas não queria que fosse assim. Ainda mais por ter visto tantas pessoas na internet que dizem ter conseguido obter essa informação via reflection.
Alguém mais tem idéia?
infelizmente, nao da pra fazer isso!! voce vai precisar pegar a classe via parametro Class, ou String.
Aqui tem dois posts que podem te ajudar a entender a questao. Esse vala da tentativa que voce ta fazendo, que funciona caso a sua classe seja estendida:
http://blog.caelum.com.br/2006/10/29/brincando-com-generics-o-bizarregenericdao/
E esse fala sobre a reificacao, que é o que voce gostaria que o java tivesse pra te ajudar:
http://blog.caelum.com.br/2007/04/08/generics-inferencia-de-tipos-e-reificacao-no-java-7/
Aqui tem uma quantidade grande de pessoas, que como eu e voce, gostaria de que tivesse reificacao no java:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5098163
Muito obrigado pelo esclarecimento. Descobri que havia alguns erros no meu código mas usando o primeiro link passado já solucionou o meu problema. Eu adicionei a minha interface DAO um método para recuperar a classe do objeto e na implementação generica usei o código que haviam passado que utilizado o “ParameterizedType” e funcionou como eu queria.
Mais uma vez, obrigado
nightmare , você pode postar o código que funcionou, por favor?
Eu ainda não entendi como foi possível…
Obrigado.
Vamos lá:
Primeiro um Bean qualquer (Us.java):
public class Us {
private String nome;
private String sobrenome;
public final String getNome() {
return nome;
}
public final void setNome(String nome) {
this.nome = nome;
}
public final String getSobrenome() {
return sobrenome;
}
public final void setSobrenome(String sobrenome) {
this.sobrenome = sobrenome;
}
}
Depois uma interface (Int.java):
public interface Int<T> {
public Class<T> getObjectClass();
/** outros metodos **/
}
Depois vamos implementá-la (Impl.java):
[code]import java.lang.reflect.ParameterizedType;
public class Impl implements Int {
private Class objectClass;
@SuppressWarnings("unchecked")
public Impl() {
super();
//coloquei no construtor por mero comodismo, podia ser uma método mesmo
this.objectClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}
@Override
public Class<T> getObjectClass() {
return objectClass;
}
}
[/code]
Vamos testar, classe Main (Main.java):
[code]
public class Main {
public static void main(String[] args) {
Int xxx = new Impl(){};
//Irá retornar “Us”… que era o que eu precisava
System.out.println(xxx.getObjectClass().getSimpleName());
}
public Main() {
super();
}
}[/code]
Basicamente foi isso que fiz e funcionou como eu queria. Ele retornou a String Us que o nome de minha classe generica passada como parametro. Não me atentei a detalhes de padrão, e preferi ao invés de copiar meu código fazer outro bem simples para ficar visível o que fiz. Espero ter ajudado.
Valeu pelo código, ajudou mto.
Obrigado.
Interessante, no caso criaste uma classe anonima que já herda BaseDAO assi utilizando a mesma.
Gostei da solução.