Como determinar a class de um tipo genérico?

Estou criando uma class genérica e em um dos methods eu preciso conhecer a class do tipo genérico atualmente em uso. A razão é que um dos methods que eu chamo espera isso como um argumento.

Exemplo:

public class MyGenericClass { public void doSomething() { // Snip... // Call to a 3rd party lib T bean = (T)someObject.create(T.class); // Snip... } } 

Claramente, o exemplo acima não funciona e resulta no seguinte erro: Literal de class ilegal para o parâmetro de tipo T.

Minha pergunta é: alguém conhece uma boa alternativa ou solução alternativa para isso?

   

Ainda os mesmos problemas: As informações genéricas são apagadas em tempo de execução, não podem ser recuperadas. Uma solução é passar a class T no parâmetro de um método estático:

 public class MyGenericClass { private final Class clazz; public static  MyGenericClass createMyGeneric(Class clazz) { return new MyGenericClass(clazz); } protected MyGenericClass(Class clazz) { this.clazz = clazz; } public void doSomething() { T instance = clazz.newInstance(); } } 

É feio, mas funciona.

Eu estava apenas apontando para esta solução:

 import java.lang.reflect.ParameterizedType; public abstract class A { public Class g() throws Exception { ParameterizedType superclass = (ParameterizedType) getClass().getGenericSuperclass(); return (Class) superclass.getActualTypeArguments()[0]; } } 

Isso funciona se A receber um tipo concreto por uma subclass:

 new A() {}.g() // this will work class B extends A {} new B().g() // this will work class C extends A {} new C().g() // this will NOT work 

Infelizmente, a solução de Christoph, conforme escrita, funciona apenas em circunstâncias muito limitadas. [EDIT: como comentado abaixo não me lembro mais do meu raciocínio para esta frase e é provável que errado: “Note que isso só funcionará em classs abstratas, em primeiro lugar.”] A próxima dificuldade é que g() só funciona de DIRECT subclasss de A Nós podemos consertar isso, no entanto:

 private Class< ?> extractClassFromType(Type t) throws ClassCastException { if (t instanceof Class< ?>) { return (Class< ?>)t; } return (Class< ?>)((ParameterizedType)t).getRawType(); } public Class g() throws ClassCastException { Class< ?> superClass = getClass(); // initial value Type superType; do { superType = superClass.getGenericSuperclass(); superClass = extractClassFromType(superType); } while (! (superClass.equals(A.class))); Type actualArg = ((ParameterizedType)superType).getActualTypeArguments()[0]; return (Class)extractClassFromType(actualArg); } 

Isso funcionará em muitas situações na prática, mas não o tempo todo. Considerar:

 public class Foo> extends A {} (new Foo>() {}).g(); 

Isso lançará um ClassCastException , porque o argumento de tipo aqui não é uma Class ou um ParameterizedType em tudo; é o TypeVariable T Então, agora você estaria preso tentando descobrir que tipo T deveria representar, e assim por diante na toca do coelho.

Eu acho que a única resposta razoável e geral é algo parecido com a resposta inicial de Nicolas – em geral, se sua class precisa instanciar objects de alguma outra class que é desconhecida em tempo de compilation, usuários de sua class precisam passar essa class literal ( ou, talvez, uma Factory) para sua class explicitamente e não depender exclusivamente de genéricos.

Eu acho uma outra maneira de obter a class do object genérico

 public Class< ?> getGenericClass(){ Class< ?> result =null; Type type =this.getClass().getGenericSuperclass(); if(type instanceofParameterizedType){ ParameterizedType pt =(ParameterizedType) type; Type[] fieldArgTypes = pt.getActualTypeArguments(); result =(Class< ?>) fieldArgTypes[0]; } return result; } 

Eu elaborarei a solução de Christoph.

Aqui está a class abstrata ClassGetter:

 private abstract class ClassGetter { public final Class get() { final ParameterizedType superclass = (ParameterizedType) getClass().getGenericSuperclass(); return (Class)superclass.getActualTypeArguments()[0]; } } 

Aqui está um método estático que usa a class acima para encontrar um tipo de class genérica:

 public static  Class getGenericClass() { return new ClassGetter() {}.get(); } 

Como exemplo de uso, você poderia fazer este método:

 public static final  T instantiate() { final Class clazz = getGenericClass(); try { return clazz.getConstructor((Class[])null).newInstance(null); } catch (Exception e) { return null; } } 

E então use isto assim:

 T var = instantiate(); 

T pode ser resolvido facilmente usando o TypeTools :

 Class t = (Class) TypeResolver.resolveRawArguments( MyGenericClass.class, getClass()); 

class pública DatabaseAccessUtil {

 EntityManagerFactory entitymanagerfactory; EntityManager entitymanager; public DatabaseAccessUtil() { entitymanagerfactory=Persistence.createEntityManagerFactory("bookmyshow"); entitymanager=entitymanagerfactory.createEntityManager(); } public void save (T t) { entitymanager.getTransaction().begin(); entitymanager.persist(t); entitymanager.getTransaction().commit(); } public void update(T t) { entitymanager.getTransaction().begin(); entitymanager.persist(t); entitymanager.getTransaction().commit(); } public void delete(T t) { entitymanager.getTransaction().begin(); entitymanager.remove(t); entitymanager.getTransaction().commit(); } public Object retrieve(Query query) { return query.getSingleResult(); } //call the method - retrieve(object,requiredclass.class) public Object retrieve(Object primaryKey,class clazz) throws Exception { return entitymanager.find(clazz,primaryKey); } 

}