2010-07-08 14 views
27

En mi proyecto actual, he sentido la necesidad de crear una especie de sistema de devolución de llamada simulada en Java utilizando la reflexión. Sin embargo, tengo problemas para que mi reflejo funcione realmente. El código de la culpa sigue:Java: NoSuchMethodException cuando el método existe claramente

public Callback(Object parentObj, String methodName, Class<?>...parameters) 
{ 
    if(parentObj == null) 
     throw new IllegalArgumentException("parentObj cannot be null", new NullPointerException()); 

    Class<?> clazz = parentObj.getClass(); 

    // Trace debugging, see output 
    for(Method m : clazz.getDeclaredMethods()) 
     if(m.getName().equals("myMethod")) System.out.println (m); 

    try { this.method = clazz.getMethod(methodName, parameters); } 
    catch(NoSuchMethodException nsme) { nsme.printStackTrace(); } // Exception caught 
    catch(SecurityException se) { se.printStackTrace(); } 

    this.parentObj = parentObj; 
    this.parameters = parameters; 
} 

Cuando construyo el objeto Callback, estoy usando una sintaxis como esta:

new Callback(this, "myMethod", boolean.class) 

Cuando intento crear mi seudo-llamada de retorno, que golpea la captura NoSuchMethodException bloquear. He incluido alguna depuración de rastreo arriba para mostrar el error de uno de mis métodos. La salida:

private void my.package.MyClass.myMethod(boolean) 
java.lang.NoSuchMethodException: my.package.MyClass.myMethod(boolean) 
    at java.lang.Class.getMethod(Class.java:1605) 
    at my.package.other.Callback.<init>(Callback.java:63) 

No pude resolver el problema, así que comencé a buscar, con poco éxito. Lo mejor que pude encontrar fue la mención del conflicto de versiones entre el JAR compilado y el tiempo de ejecución. Sin embargo, MyJar.jar/META-INF/MANIFEST.MF contiene Created-By: 1.6.0_02 (Sun Microsystems Inc.). Mi IDE está ejecutando C:\Program Files\Java\jdk1.6.0_02\bin\javac.exe para compilar mi proyecto. Estoy usando C:\Program Files\Java\jdk1.6.0_02\bin\java.exe para ejecutar mi JAR.

No entiendo por qué Class.getMethod afirma que el método no existe, pero Class.getMethods parece no tener problemas para encontrarlo. ¿Ayuda? :(

+1

Es por eso que no confía en Reflection, que no es confiable en el mejor de los casos. – quantumSoup

+0

No diría que no es confiable, pero puede ser complicado e ineficiente. –

+1

Sin duda es menos confiable que algo que tu compilador puede probar que es correcto. :-) –

Respuesta

86

Su método es privado, pero getMethod() solo devuelve el método público.

Necesita usar getDeclaredMethod().

+0

¡Sí! Esto solucionó el problema sin obligarme a usar métodos públicos. ¡Gracias! –

+3

3 años después ... Eso tiene mucho sentido en mi caso. Aunque comencé a leer la documentación de ambos métodos en http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Class.html#getMethod(java.lang.String, java.lang. Clase ...) y no mencionan dicha información. ¿Tal vez investigaste el código? Bien por usted. +1 – Mzn

+0

Estaba golpeando mi cabeza contra la pared durante 2 horas seguidas. Gracias hombre ! –

0

El problema de versiones que pueden causar NoSuchMethodException no es una diferencia entre las versiones del compilador. Es una diferencia en la versión de (en su caso) MyClass en tiempo de compilación en tiempo de ejecución frente.

Ya que estás Sin embargo, el uso de la reflexión no podría tener nada que ver con el control de versiones. Sin duda, eso no explicaría el comportamiento diferente entre getMethod y getDeclaredMethods, porque los está ejecutando contra la misma instancia de Clase, por lo tanto, una diferencia de versión no es realmente posible

¿Está seguro de que los parámetros coinciden con su método real?

4

El Javadoc para getMethod no es explícito, pero parece que podría arrojar una NoSuchMethodException para los métodos que no son públicos, y su método es privado.

+2

Sí, eso es todo. Tu sugerencia me hizo verter a través del código fuente de Class. 'getMethod' calls (private)' getMethod0'.'getMethod0' llama a' privateGetDeclaredMethods (true) ', donde' true' es "' publicOnly' " –

1

Necesita que la lista de parámetros sea absolutamente correcta para el método que desee para que la llamada tenga éxito.

He descubierto que los pequeños pasos son importantes cuando se reflexiona porque el compilador no ayuda. Escriba un pequeño fragmento que realmente invoque exactamente el método que desea en este caso particular, y luego, cuando eso funcione, generalícelo en el marco aquí. Me centraría en los parámetros aprobados.

Cuestiones relacionadas