Java getMethod con parámetro de subclase

Estoy escribiendo una biblioteca que utiliza la reflexión para buscar y llamar a los métodos de forma dinámica. Dado solo un objeto, un nombre de método y una lista de parámetros, necesito llamar al método dado como si la llamada al método estuviera explícitamente escrita en el código.

He estado usando el siguiente enfoque, que funciona en la mayoría de los casos:

static void callMethod(Object receiver, String methodName, Object[] params) { Class[] paramTypes = new Class[params.length]; for (int i = 0; i < param.length; i++) { paramTypes[i] = params[i].getClass(); } receiver.getClass().getMethod(methodName, paramTypes).invoke(receiver, params); } 

Sin embargo, cuando uno de los parámetros es una subclase de uno de los tipos admitidos para el método, la API de reflexión arroja una NoSuchMethodException . Por ejemplo, si la clase del receptor tiene el testMethod(Foo) definido, falla lo siguiente:

 receiver.getClass().getMethod("testMethod", FooSubclass.class).invoke(receiver, new FooSubclass()); 

a pesar de que esto funciona:

 receiver.testMethod(new FooSubclass()); 

¿Cómo resuelvo esto? Si la llamada al método está codificada, no hay problema: el comstackdor simplemente usa el algoritmo de sobrecarga para elegir el mejor método aplicable para usar. No funciona con la reflexión, sin embargo, que es lo que necesito.

¡Gracias por adelantado!

Es un poco más largo de lo que comenzaste, pero esto hace lo que pediste … y un poco más además – por ejemplo, callMethod (receiver, “voidMethod”) donde voidMethod no tiene argumentos también funciona.

 static void callMethod(Object receiver, String methodName, Object... params) { if (receiver == null || methodName == null) { return; } Class cls = receiver.getClass(); Method[] methods = cls.getMethods(); Method toInvoke = null; methodLoop: for (Method method : methods) { if (!methodName.equals(method.getName())) { continue; } Class[] paramTypes = method.getParameterTypes(); if (params == null && paramTypes == null) { toInvoke = method; break; } else if (params == null || paramTypes == null || paramTypes.length != params.length) { continue; } for (int i = 0; i < params.length; ++i) { if (!paramTypes[i].isAssignableFrom(params[i].getClass())) { continue methodLoop; } } toInvoke = method; } if (toInvoke != null) { try { toInvoke.invoke(receiver, params); } catch (Exception t) { t.printStackTrace(); } } } 

 receiver.testMethod(new FooSubclass()); even though this works: 

Si su función testMethod tiene un parámetro de tipo FooSuperClass :

  public void testMethod(FooSuperClass object){} 

luego, mientras intenta obtener un método coincidente con reflection: getClass().getMethod("testMethod", FooSubclass.class) dará como resultado NoSuchMethodException . Debido a que getMethod(String name, Class... parameterTypes function devuelve un objeto Method que es un método miembro público con el name dado donde parameterTypes es una matriz de objetos Class que identifica los tipos de parámetros formales del método. dicho método no se declara con la firma testMedthod(FooSubClass object) ya que el tipo de parámetro formal de la función es FooSuperClass . Por lo tanto, la invocación correcta es:

 receiver.getClass().getMethod("testMethod", FooSuperClass.class) .invoke(receiver, new FooSubclass()); 

o pasando la SubClass.class.getSuperClass() llamar a SubClass.class.getSuperClass() siguiente manera:

 receiver.getClass().getMethod("testMethod", FooSubClass.class.getSuperclass()) .invoke(receiver, new FooSubclass()); 

o , cambiando la firma del método a: public void testMethod(FooSubClass object){} y luego invocar como lo está haciendo ahora:

 receiver.getClass().getMethod("testMethod", FooSubclass.class) .invoke(receiver, new FooSubclass());