¿Cómo determinar la clase de un tipo genérico?

Estoy creando una clase genérica y en uno de los métodos necesito saber la Clase del tipo genérico actualmente en uso. La razón es que uno de los métodos que llamo espera esto como un argumento.

Ejemplo:

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

Claramente, el ejemplo anterior no funciona y da como resultado el siguiente error: literal de clase ilegal para el parámetro de tipo T.

Mi pregunta es: ¿alguien sabe una buena alternativa o solución alternativa para esto?

Siguen los mismos problemas: las informaciones genéricas se borran en el tiempo de ejecución, no se pueden recuperar. Una solución es pasar la clase T en el parámetro de un 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(); } } 

Es feo, pero funciona.

Me acaba de señalar a esta solución:

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

Esto funciona si a A se le asigna un tipo concreto por una subclase:

 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 

Desafortunadamente, la solución de Christoph tal como está escrita solo funciona en circunstancias muy limitadas. [EDITAR: como se comenta a continuación, ya no recuerdo mi razonamiento para esta frase y es probable que esté equivocado: “Tenga en cuenta que esto solo funcionará en clases abstractas, en primer lugar.”] La siguiente dificultad es que g() solo funciona desde DIRECT subclases de A Podemos arreglar eso, sin embargo:

 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); } 

Esto funcionará en muchas situaciones en la práctica, pero no TODO el tiempo. Considerar:

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

Esto lanzará una ClassCastException , porque el argumento de tipo aquí no es una Class o un tipo ParameterizedType en absoluto; es el TypeVariable T Así que ahora estarías atrapado tratando de descubrir qué tipo de T supuestamente representa, y así sucesivamente en el agujero del conejo.

Creo que la única respuesta razonable y general es algo parecido a la respuesta inicial de Nicolas: en general, si tu clase necesita instanciar objetos de otra clase desconocida en tiempo de comstackción, los usuarios de tu clase deben pasar esa clase literal ( o, tal vez, una fábrica) a su clase de forma explícita y no depender únicamente de los generics.

encuentro otra forma de obtener la Clase del objeto 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; } 

Elaboraré la solución de Christoph.

Aquí está la clase abstracta de ClassGetter:

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

Aquí hay un método estático que usa la clase anterior para encontrar un tipo de clase genérico:

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

Como un ejemplo de su uso, puedes hacer 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; } } 

Y luego úsalo así:

 T var = instantiate(); 

T se puede resolver fácilmente usando TypeTools :

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

clase 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); } 

}