Quiero lograr algo como esto en Java, pero obtengo un error de tiempo de compilación:
El método onMessage(TextMessage, Class) en el tipo AbstractTestLoader no es aplicable para los argumentos (TextMessage, Class)
Entiendo el motivo de ese error, pero también siento que debería haber alguna forma de lograr esto con el casting o puede ser de otra manera.
public abstract class AbstractTestLoader<T extends AbstractEntity<T>> { public void onMessage(TextMessage message) throws Exception { onMessage(message, this.getClass()); // I want to correct this line in such a way so that I can call below method with actual Class of {T extends AbstractEntity<T>} } public void onMessage(TextMessage message, Class<T> clazz) throws Exception { //here my original logic will go } }Debe tenerse en cuenta que, si bien el genérico de Java se borró en el tiempo de ejecución, existen API de reflexión limitadas para recuperarlas si están presentes en el archivo de clase.
Aquí hay una solución rápida con estas suposiciones:
AbstractTestLoader es la superclase directa.class GenericLoader<T extends SubclassAbstractEntity<T>> extends AbstractTestLoader<T> no existe.Aquí está el código:
public class AbstractTestLoader<T extends AbstractEntity<T>> { private static final ClassValue<Class<?>> TYPE_PARAMETER_CACHE = new ClassValue<Class<?>>() { @Override protected Class<?> computeValue(Class<?> type) { assert AbstractTestLoader.class.isAssignableFrom(type); assert type.getSuperclass() == AbstractTestLoader.class; Type genericSuperclass = type.getGenericSuperclass(); assert genericSuperclass instanceof ParameterizedType; Type entityType = ((ParameterizedType) genericSuperclass).getActualTypeArguments()[0]; assert entityType instanceof Class<?>; return (Class<?>) entityType; } }; @SuppressWarnings("unchecked") protected Class<T> getEntityType() { return (Class<T>) TYPE_PARAMETER_CACHE.get(this.getClass()); } public void onMessage(Object message) throws Exception { onMessage(message, getEntityType()); // getting compile time error here } public void onMessage(Object message, Class<T> clazz) throws Exception { //here my original logic will go } } El getEntityType se puede anular en las subclases donde esas dos suposiciones fallan.
Finalmente, después de un par de intentos, obtuve una solución simple y funcional, pero aún estoy abierto a escuchar otras mejores respuestas si es posible. Gracias
public abstract class AbstractTestLoader<T extends AbstractEntity<T>> { abstract Class<T> getEntityType(); public void onMessage(TextMessage message) throws Exception { onMessage(message, getEntityType()); } public void onMessage(TextMessage message, Class<T> clazz) throws Exception { //here my original logic will go } }Java implementa genéricos a través del borrado de tipos , lo que significa que es solo un concepto de tiempo de compilación. Cuando el programa se está ejecutando, no hay diferencia entre AbstractTestLoader<Foo> y AbstractTestLoader<Bar> .
Hay algunas soluciones, como la que descubrió, en las que una clase que es consciente del tipo de T en tiempo de compilación se puede hacer para proporcionar un tipo de clase real. Pero no hay forma de usar genéricos puros para descubrir cuál es el tipo genérico en tiempo de ejecución.