2010-07-08 6 views
27

In meinem aktuellen Projekt habe ich das Bedürfnis verspürt, eine Art simuliertes Callback-System in Java mittels Reflektion zu erstellen. Ich habe jedoch Probleme damit, dass mein Spiegelbild funktioniert. Der Code auf Fehler folgt:Java: NoSuchMethodException, wenn Methode eindeutig existiert

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

Wenn ich das Callback Objekt konstruieren, ich Syntax wie folgt bin mit:

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

Wenn ich versuche, meinen pseudo-Rückruf zu erstellen, es trifft den NoSuchMethodException Fang Block. Ich habe oben ein Debugging für die Ablaufverfolgung eingefügt, um zu zeigen, dass die Ausgabe einer meiner Methoden fehlschlägt. Die Ausgabe:

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) 

Ich konnte das Problem nicht herausfinden, also fing ich an zu jagen, zu wenig Nutzen. Das Beste, was ich finden konnte, war der Versionskonflikt zwischen der kompilierten JAR und der Laufzeit. Jedoch enthält MyJar.jar/META-INF/MANIFEST.MFCreated-By: 1.6.0_02 (Sun Microsystems Inc.). Meine IDE läuft C:\Program Files\Java\jdk1.6.0_02\bin\javac.exe, um mein Projekt zu kompilieren. Ich verwende C:\Program Files\Java\jdk1.6.0_02\bin\java.exe, um meine JAR zu starten.

Ich bin ratlos, warum Class.getMethod behauptet, die Methode existiert nicht, aber Class.getMethods scheint kein Problem zu haben, es zu finden. Hilfe? :(

+1

Deshalb verlassen Sie sich nicht auf Reflection, die bestenfalls unzuverlässig ist. – quantumSoup

+0

Ich würde nicht sagen, dass es unzuverlässig ist, aber es kann kompliziert und ineffizient sein. –

+1

Es ist sicherlich weniger zuverlässig als etwas, das Ihr Compiler beweisen kann, ist richtig. :-) –

Antwort

86

Ihre Methode ist privat, aber getMethod() gibt nur öffentliche Methode zurück.

Sie müssen getDeclaredMethod() verwenden.

+0

Ja! Dies behebt das Problem, ohne dass ich gezwungen bin, öffentliche Methoden zu verwenden. Vielen Dank! –

+3

3 Jahre später ... Das macht in meinem Fall viel Sinn. Obwohl ich anfing, die Dokumentation für beide Methoden zu lesen, siehe http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Class.html#getMethod(java.lang.String, java.lang. Klasse ...) und sie erwähnen solche Informationen nicht. Vielleicht haben Sie sich den Code angesehen? Schön für dich. +1 – Mzn

+0

Hämmerte meinen Kopf für 2 Stunden direkt auf die Wand. Danke, Mann ! –

0

Die Versionierung Problem, das kann dazu führen, NoSuchMethodException ist kein Unterschied zwischen den Compiler-Versionen. Es ist ein Unterschied in der Version von (in Ihrem Fall) MyClass bei der Kompilierung im Vergleich zu Laufzeit.

Da du bist Bei der Verwendung von Reflection haben Sie jedoch möglicherweise nichts mit der Versionierung zu tun. Natürlich würde dies kein unterschiedliches Verhalten zwischen getMethod und getDeclaredMethods erklären, da Sie sie gegen dieselbe Klasseninstanz ausführen, daher ist ein Versionsunterschied nicht wirklich möglich.

Sind Sie sicher, dass die Parameter Ihrer tatsächlichen Methode entsprechen?

4

Das Javadoc für getMethod ist nicht explizit, aber es sieht so aus, als könnte es eine NoSuchMethodException für Methoden werfen, die nicht öffentlich sind, und Ihre Methode ist privat.

+2

Yup, das ist es. Dein Vorschlag ließ mich den Quellcode für Class durchgehen. 'getMethod' ruft (private)' getMethod0'.'getMethod0' ruft' privateGetDeclaredMethods (true) 'auf, wobei' true' '' publicOnly' ist. –

1

Sie müssen die Parameterliste für die gewünschte Methode absolut korrekt haben, damit der Aufruf erfolgreich ist.

Ich habe festgestellt, dass kleine Schritte wichtig sind, wenn Sie Reflektionen machen, weil der Compiler nicht hilft. Schreiben Sie ein kleines Snippet, das genau die Methode aufruft, die Sie wollen, und dann, wenn das funktioniert, verallgemeinern Sie es in das Framework hier. Ich würde mich auf die übergebenen Parameter konzentrieren.

Verwandte Themen