Reflection: getMethods schlägt fehl (NoClassDefFoundE))

bdorninger

Mitglied
Annahme: Wir haben eine Klasse "MyClassToCheck" (siehe code Snippet unten)

Von einer Anwendung aus möchte ich prüfen, od diese Klasse Methoden bietet, die einer bestimmten Signatur folgen. Dabei kann ich aber die Verfügbarkeit aller im Code dieser Klasse verwendeten Typen nicht voraussetzen. (symbolisiert durch unten verwendete "ClassNotOnClasspath")
In dieser Anwendung hol ich mir die zu überprüfende Klasse mit "Class.forName" und ruf dann getMethods() auf.

....
cl = Class.forName("checkit.MyClassToCheck");
Method[] meth=cl.getMethods();
....

Klarerweise darf die Klasse keinen static member von "ClassNotOnClasspath" haben.
Aber warum endet der call mit einem NCDFE, wenn eine Var dieses Typs innerhalb eines try-catch Blocks deklariert wird? ???:L
Kann jemand von Euch Gurus für Aufklärung sorgen ?

Thx,
Bernhard

---------------------------------------------------
Java:
package checkit;

import refl.ReflTest2.AnotherParamOnClassPath;
import refl.ReflTest2.ParamOnClassPath;
import refl.ReflTest2.RetValOnClassPath;
import tocheck.ClassNotOnClassPath;

class MyClassToCheck
{
    ClassNotOnClassPath instance_member1=new ClassNotOnClassPath();;  // --> WORKS !!
    //static ClassNotOnClassPath static_member1=new ClassNotOnClassPath();  // --> DOES NOT WORK which is comprehensible!!


    public RetValOnClassPath myMethodName( ParamOnClassPath par1, AnotherParamOnClassPath par2)
    {
        ClassNotOnClassPath local=new ClassNotOnClassPath();  // --> WORKS !!
        
        if(System.getProperty("aProperty")!=null)
        {
            ClassNotOnClassPath blocklocal=new ClassNotOnClassPath();  // --> WORKS !!
            System.out.println(blocklocal);
        }
        
        try {
            //ClassNotOnClassPath trylocal=new ClassNotOnClassPath();  // DOES NOT WORK  !!!
            RetValOnClassPath rv=new RetValOnClassPath();
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
        
        return new RetValOnClassPath();
    }
}
 
static Attribute werden vom ClassLoader initialisiert, zu diesem Zeitpunkt ist die ClassNotOnClassPath noch gar nicht manuell geladen worden, ist ja schliesslich nicht im Classpath 😉
 
static Attribute werden vom ClassLoader initialisiert, zu diesem Zeitpunkt ist die ClassNotOnClassPath noch gar nicht manuell geladen worden, ist ja schliesslich nicht im Classpath 😉

Naja, DAS ist mir klar - das steht auch in meiner Anfrage und im Src code comment ist das auch nochmal erwähnt.
Was NICHT klar ist, warum eine lokale Decl im try-catch Block Probleme verrusacht. Dahin ging auch meine Frage
 
Bei mir macht das keine Probleme.

Java:
package de.mvitz.example.java.reflection.incomplete_cp;

public final class NotOnClassPath {
}

Java:
package de.mvitz.example.java.reflection.incomplete_cp;

public final class OnClassPath {

    public String myMethod() {
        try {
            new NotOnClassPath();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return "Foo";
    }

}

Java:
package de.mvitz.example.java.reflection.incomplete_cp;

import java.util.Arrays;

public final class Main {

    public static void main(String[] args) throws Exception {
        Class<?> clazz = Class.forName("de.mvitz.example.java.reflection.incomplete_cp.OnClassPath");
        System.out.println(Arrays.asList(clazz.getMethods()));
    }

}
 
Du hast in Deinem code aber keine Deklaration.
ein new ohne Zuweisung ist etwas sinnlos.

Relativieren muss ich allerdings: Bereits class.forName auf die eigentlich existierende MyClassToCheck schlägt mit einem NCDFE fehl und nicht erst getMethods().
Grund für meine etwas irreführende Aussage ist, dass der ursprüngliche Code in einer OSGi Umgebung läuft. In der verwende ich einen speziellen Classloader, der die zu prüfende Klasse (korrekt oder auch nicht) erkennt und ein Class Object bereitstellt. Dort schlägt aber dann eben getMethods fehl.

Doch das Grundproblem bleibt das selbe.
Ich müh mich grad ein wenig durch die VM spec, aber bin bisher nicht schlauer geworden.

Thanx aber vorerst mal für Eure Bemühungen. Weitere Erkenntnisse werden natürlich gerne entgegengenommen 😉

Bei mir macht das keine Probleme.
 
Zuletzt bearbeitet:
Natürlich macht new ohne Zuweisung Sinn, wenn das Object z.B. etwas mit Seiteneffekten macht, ohne das man die Instanz braucht. Ist aber für diesen Fall völlig egal:

Java:
package de.mvitz.example.java.reflection.incomplete_cp;

public final class NotOnClassPath {
    public void doSomething() { System.out.println("NotOnClassPath.doSomething"); }
}

Java:
package de.mvitz.example.java.reflection.incomplete_cp;

public final class OnClassPath {

    public String myMethod() {
        try {
            final NotOnClassPath object = new NotOnClassPath();
            object.doSomething();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return "Foo";
    }

}

Main wie vorher --> funktioniert weiterhin ohne Probleme.

[EDIT]Vermutlich liegt das Problem dann eher an einer deiner anderen Änderungen.
Hättest ruhig direkt erwähnen können, dass du dich a) in einer OSGI Umgebung bewegst und b) sogar einen eigenen ClassLoader verwendest.[/EDIT]
 
Natürlich macht new ohne Zuweisung Sinn, wenn das Object z.B. etwas mit Seiteneffekten macht, ohne das man die Instanz braucht. Ist aber für diesen Fall völlig egal:
Ja, dann schon. Würde ich persönlich aber als bad style bezeichnen - für sowas gäb es nämlich static Methoden

..funktioniert weiter....

Vermutlich liegt das Problem dann eher an einer deiner anderen Änderungen.
Hättest ruhig direkt erwähnen können, dass du dich a) in einer OSGI Umgebung bewegst und b) sogar einen eigenen ClassLoader verwendest.

Der letzte gepostete Code von Dir funktioniert bei mir unter J6/27 und J7/1 nicht. Der ohne Decl schon.
Wie führst du das Beispiel bei Dir aus?

Bezüglich "anderer Änderungen":
Das ist nicht der Fall, da sich mein Beispiel wie gesagt auch ausserhalb eines OSGi Container nachvollziehen lässt - siehe meinen geposteten Code.
Zusätzlich habe ich ein ausführbares Jar inkl. Sourcen drangehängt - falls es Dich interessiert.

lg,
Bernhard
 
JDK 1.6.0_30 als Maven Projekt.
Ausführung sowohl über die Kommandozeile, als auch über Eclipse.

Auch per
Code:
javac -version
#javac 1.7.0

java -version
#java version "1.7.0"
#Java(TM) SE Runtime Environment (build 1.7.0-b147)
#Java HotSpot(TM) Client VM (build 21.0-b17, mixed mode, sharing)

keine Probleme.
 
Hmm. eigenartig. Kannst Du mir ein executable Jar zukommen lassen?
Über Eclipse funktionierts bei mir auch - was ja klar ist da man ja zum kompilieren die NotOnCP Klassen braucht und Eclipse dann ja die auch den Build CP in den Run CP übernimmt.

Thx,
Bernhard

JDK 1.6.0_30 als Maven Projekt.
Ausführung sowohl über die Kommandozeile, als auch über Eclipse.

Auch per
Code:
javac -version
#javac 1.7.0

java -version
#java version "1.7.0"
#Java(TM) SE Runtime Environment (build 1.7.0-b147)
#Java HotSpot(TM) Client VM (build 21.0-b17, mixed mode, sharing)

keine Probleme.
 
In diesem Falle ist das bei Eclipse nicht der Fall, da ich 3 Projekte habe und Main nur auf OnCp verweist, nicht aber auf NotOnCp. OnCp verweist zwar auf NotOnCp, exportiert dieses aber nicht.

Anbei die 3 Binaries (müssten die mit 1.7 kompilierten sein).
 

Anhänge

In diesem Falle ist das bei Eclipse nicht der Fall, da ich 3 Projekte habe und Main nur auf OnCp verweist, nicht aber auf NotOnCp. OnCp verweist zwar auf NotOnCp, exportiert dieses aber nicht.

Anbei die 3 Binaries (müssten die mit 1.7 kompilierten sein).

Besten Dank. Nun kommen wir der Antwort etwas näher.
Mit J6 und J7 (auf J6/7 source/class compliance) compiliert funktioniert Dein und auch mein Beispiel.
Der Build des Projekts erfolgt aber nach Rücksprache beim Kunden mit Java 5 compiler compliance-die haben noch nicht flächendeckend auf 6 umgestellt.

Dann scheint das wohl in früheren Versionen des Compilers ein Bug zu sein.....

Das Problem ist damit noch nicht ganz gelöst, aber da muss man halt dann am Deployment Szenario drehen.
 
Zuletzt bearbeitet:
Stimmt,

kompiliert mit 1.6 auf 1.5 Kompatibilität und ausgeführt mit 1.6 --> NCDFE
kompiliert mit 1.5 auf 1.5 Kompatibilität und ausgeführt mit 1.5 --> NCDFE
 
Stimmt,

kompiliert mit 1.6 auf 1.5 Kompatibilität und ausgeführt mit 1.6 --> NCDFE
kompiliert mit 1.5 auf 1.5 Kompatibilität und ausgeführt mit 1.5 --> NCDFE

wie gesagt - Gesamtproblem nicht zu 100% gelöst, aber unsere Diskussion hat Licht in die Sache gebracht - deswegen nochmal Danke

Übrigens im selben Zeitraum auf die gleiche Frage in den Oracle Java foren NULL Resonanz...
 
Wäre theoretisch möglich. Aber mvitz hat das ja schon beantwortet, deshalb spare ich mir den Versuch. Nachdem es sich so deutlich am Compliance Level zeigt und nicht am Compiler-release vermute ich da aber eher den "Fehler" im Bytecode.

lg,
Bernhard
 

Zurück
Oben