Estoy trabajando en una invocación dinámica de código a través de un intérprete, y estoy entrando en las áreas desagradables y pegajosas de la resolución de métodos como se describe en JLS section 15.12.Java: resolución de método de tiempo de ejecución
La manera "fácil" de elegir un método es cuando conoce los tipos exactos de todos los argumentos, en cuyo punto puede usar Class.getDeclaredMethod(String name, Class[] parameterTypes)
. Tal vez tenga que verificar la accesibilidad del método y las superclases/superinterfaces de la clase.
Pero esto no cubre cualquiera de los siguientes casos, por lo que es algo inútil:
- boxeo/primitivas unboxing
- subtipos
- varargs
- un argumento nulo (que puede ser cualquier tipo, a menos que el intérprete sepa lo contrario; en tiempo de compilación, cualquier ambigüedad sería eliminar al convertir nulo a una clase/interfaz)
- conversión de tipo primitivo (no es parte de Java, pero está permitida en contexto de idiomas - p. Rhino Javascript donde todos los números son de punto flotante, por lo que el código Java podría tomar una
int
pero la persona que llama que pasa en un número que es o bien unint
o unadouble
)
(ver más abajo para un ejemplo rápido de la primera tres)
así que ahora tengo que escribir mi propia biblioteca de resolución de métodos ...
¿hay alguna biblioteca marco conocido para ayudar en esto?
package com.example.test.reflect;
import java.lang.reflect.Method;
public class MethodResolutionTest {
public void compute(int i) { /* implementation... */ }
public void compute(Long l) { /* implementation... */ }
public void compute(Object obj) { /* implementation... */ }
public void compute(String... strings) { /* implementation... */ }
public static void main(String[] args) {
Class<?> cl = MethodResolutionTest.class;
/* these succeed */
findAndPrintMethod(cl, "compute", int.class);
findAndPrintMethod(cl, "compute", Long.class);
findAndPrintMethod(cl, "compute", Object.class);
findAndPrintMethod(cl, "compute", String[].class);
/* these fail */
findAndPrintMethod(cl, "compute", Integer.class);
findAndPrintMethod(cl, "compute", long.class);
findAndPrintMethod(cl, "compute", MethodResolutionTest.class);
findAndPrintMethod(cl, "compute", String.class, String.class);
}
private static void findAndPrintMethod(Class<?> objectClass,
String methodName, Class<?>... parameterTypes)
{
try {
Method method = findMethod(objectClass, methodName,
parameterTypes);
System.out.println(method.toString());
}
catch (SecurityException e) {
e.printStackTrace();
}
catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
private static Method findMethod(Class<?> objectClass,
String methodName, Class<?>[] parameterTypes)
throws SecurityException, NoSuchMethodException
{
return objectClass.getDeclaredMethod(methodName, parameterTypes);
}
}
[Esta respuesta maneja algunos de sus casos como subtipos] (http://stackoverflow.com/questions/2580665/java-getmethod-with-superclass-parameters-in-method/2580699#2580699). –
@Jonathon: sé de isAssignableFrom. Obtuve algo de cosecha propia trabajando con subtipos y boxeo/unboxing. Luego comencé a varargs y se puso desagradable, y pensé, "Espera un minuto, ¿por qué estoy haciendo esto?" entonces estoy buscando específicamente una biblioteca preexistente. (O al menos un buen conjunto de casos de prueba preexistentes) De lo contrario, puedo hacer esto por mi cuenta, pero es un gran dolor. –
A menos que encuentres una biblioteca dulce, creo que lo que hagas será feo y difícil de leer. –