2010-12-09 6 views
1

Ich versuche Class.forName zu verwenden, um dynamisch eine Klasse aus einer JAR-Datei auf dem Dateisystem zur Laufzeit zu laden. Die Klasse, die ich zu laden versuche, implementiert eine Schnittstelle in einer anderen .jar-Datei. Daher verwende ich meinen eigenen URLClassLoader, um auf die beiden .jars zu verweisen.Problem mit Java Class.forName

Der Code funktioniert, wenn er nicht im Kontext der Web-App aufgerufen wird (ich habe dies getestet, indem ich die Methode in ein separates Programm kopiert und eingefügt habe und von main aus aufgerufen habe). Wenn ich jedoch die Web-App starte/debugge (ich verwende NetBeans), schlägt der Code fehl. Die newInstance-Methode löst eine ClassCastException aus, wenn ich versuche, die Instanz auf die in der Datei jar_file_dependencies.jar angegebene Schnittstelle zu konvertieren.

Hier ist der relevante Code, ob das hilft:

 File gameJar = new File("C:\\file_path\\jar_file.jar"); 

     File gameDependenciesJar = new File("C:\\file_path\\jar_file_dependencies.jar"); 

     URLClassLoader cl = new URLClassLoader(new URL[] 
       { 
        gameJar.toURI().toURL(), 
        gameDependenciesJar.toURI().toURL() 
       }); 

     Class clazz = Class.forName("MyClass", true, cl); 

     IMyClass myClass = (IMyClass)clazz.newInstance(); 

     System.out.println(game); 

    } catch (Exception e) 
    { 
     System.out.println(e.getMessage()); 
    } 

Irgendwelche Vorschläge, warum dieser Code in einem Programm zu arbeiten und nicht ein anderer wäre sehr dankbar.

Vielen Dank, Dan

+1

Könnte es dieses Problem sein: http://stackoverflow.com/questions/2081000/java-lang-classcastexception-when-casting-object-result-of-java-lang-reflect-met? – Lars

+1

@Lars, ich denke das ist in der Tat das Problem. Ich würde dasselbe vorschlagen - geben Sie dem URLClassLoader einen Elternteil. –

Antwort

1

kurze Antwort, ohne gehen in viele der haarigen Details: eine oder beide der gameJar und gameDependenciesJar enthalten wahrscheinlich eine Definition der IMyClass Klasse/Schnittstelle. Die Faustregel beim Verwenden von untergeordneten Klassenladeprogrammen ist, dass der untergeordnete Klassenlader nicht irgendeine der "gemeinsam genutzten" Klassen enthalten sollte - diese sollten nur im übergeordneten Klassenlader vorhanden sein.

teilweise Erläuterung: Klassenladeprogramme für Webanwendungen haben normalerweise unterschiedliche Delegierungsrichtlinien von normalen Klassenladeprogrammen. oft ziehen sie die Klasse des Kindes der der Eltern vor. Normale Classloader bevorzugen im Allgemeinen die Klasse des Elternteils gegenüber der des Kindes. In Ihrer Webanwendung erhalten Sie zwei separate Definitionen der IMyClass-Klasse (ein def im übergeordneten Klassenlader, einen im untergeordneten). In Ihrer normalen App wird die IMyClass-Definition im Child-Classloader ignoriert, sodass nur eine Definition geladen wird (im Parent-Classloader) und alles ist glücklich.

+0

Vielen Dank! Problem gelöst!! –

0

Vielleicht wird dies helfen, (ungetestet):

ClassLoader clsLoader = Thread.currentThread().getContextClassLoader(); 
if (clsLoader == null) { 
    clsLoader = this.getClass().getClassLoader(); 
} 

URLClassLoader cl = new URLClassLoader(new URL[] 
       { 
        gameJar.toURI().toURL(), 
        gameDependenciesJar.toURI().toURL() 
       }, clsLoader); 

Auch Sie vollständigen deklarative Namen der Klasse passieren sollte MyClass statt nur es MyClass in Class.forName() aufrufen.

z.

Class clazz = Class.forName("com.xxxx.yyy.MyClass", true, cl);