Java Web Start ClassLoader Typecast Problem

mehirc

Mitglied
Hallo,

meine Anwendung wird über Java Web Start gestartet und lädt mit einem ClassLoader Plugins nach, die verpackt in jar-Dateien im Arbeitsverzeichnis liegen (zB MyPlugin.class in MyPlugin.jar).

Über die findClass-Methode des ClassLoaders werden die Plugins auch gefunden, aber ich möchte natürlich Instanzen davon haben. Die Methode newInstance() Liefert mir aber nur den Typ Object. Eigentlich sollte sich Object zu Plugin typecasten lassen, da die geladene Klasse von Plugin abgeleitet ist, aber es kommt stattdessen der Fehler: "MyPlugin cannot be cast to Plugin".

Code:
...
Plugin plugin = (Plugin)pluginLoader.findClass("MyPlugin").newInstance();
...

Der Fehler tritt auch nur dann auf, wenn die Anwendung über Java Web Start gestartet wird, irgendwas scheint da wohl anders zu laufen. Hoffe jemand hat eine Idee die mir weiterhelfen könnte.

Michael
 
Vielleicht kann jemand was mit der Fehlermeldung anfangen, ich bin immernoch ratlos:
Code:
java.lang.ClassCastException: MyPlugin cannot be cast to Plugin
	at MyMain.main(MyMain.java:93)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at com.sun.javaws.Launcher.executeApplication(Unknown Source)
	at com.sun.javaws.Launcher.executeMainClass(Unknown Source)
	at com.sun.javaws.Launcher.doLaunchApp(Unknown Source)
	at com.sun.javaws.Launcher.run(Unknown Source)
	at java.lang.Thread.run(Unknown Source)
 
Dein MyPlugin implementiert halt nicht Plugin. Zumindest laut der Fehlermeldung.

Was mich interessieren würde, ist, wie dein pluginLoader deterministisch eine nicht vollqualifizierte Klasse finden soll. Durchsuchst du dann jedes Package oder wie? Was, wenn in zwei verschiedenen Packages zwei Klassen vorhanden sind, die MyPlugin heißen?

Gruß
Ollie
 
Hi Ollie,

hier mal die Header von Plugin und MyPlugin:

Code:
public abstract class Plugin implements PluginInterface
public class MyPlugin extends Plugin

Ja, ich durchsuche einfach alle Packages. Der pluginLoader sucht sich bei der Initialisierung die jar-Dateien im Verzeichnis und registriert sie als URLs, ebenso die URL zu der eigentlichen jar-Datei des Hauptprogramms. Die Dateinamen haben den gleichen Namen wie die jeweilige Plugin-Klasse darin, also kann ich über den Dateinamen gezielt suchen.

Ich konnte auch verfolgen, dass beim Laden von MyPlugin automatisch nach den Klassen Plugin und PluginInterface weitergesucht wird. Es scheint auch alles gefunden zu werden und eine Instanz bekomme ich letztendlich ja auch. Wenn ich von der Instanz den Klassennamen abrufe zeigt er mir auch MyPlugin, und als Superklasse Plugin.

Wie gesagt vom Programm her funktioniert alles prima wenn ich es normal starte (aus eclipse bzw. über die Haupt-jar), lediglich mit Web Start bekomme ich diesen Fehler.

Da die Dateien nicht doppelt vorkommen können, kann es auch nicht passieren dass eine Plugin-Klasse mehrfach vorkommt.

Gruß,

Michael
 
Wer garantiert dir, dass nicht jemand ein JAR mit einer Klasse com.foo.MyPlugin und eins mir com.bar.MyPlugin in deinen Classpath legt? Welche Klasse wird dann genommen, wenn du MyPlugin referenzierst? Der Classloader garantiert ja keine Reihenfolge in der er sich die JARs anschaut.

Das wär das erste mir bekannte Pluginsystem, was ohne voll qualifiziere Klassennamen auskommt ;).

Gruß
Ollie
 
Ich seh da eigentlich kein Problem, wenn jemand möchte dass die Plugins richtig funktionieren, dann soll er sowas einfach nicht machen. (design by contract) ;-)

Aber vielleicht hast du mir ja einen Vorschlag wie ich das besser machen kann, ich hab mir das ja nur nach bestem Wissen zusammengeschustert und hab zuvor sowas noch nicht programmiert. So ganz versteh ich auch nicht was du mit voll qualifizierten Klassennamen meinst, wie kann ich damit sicherstellen dass dein Szenario nicht möglich ist?

Gruß
Michael
 
Hallo,

in Java sind Klassen durch das Tupel <fqcn,ClassLoader> eindeutig definiert. (fqcn = fully qualified class name). So kann man in einem System mit mehreren ClassLoadern vermeintlich die selbe Klasse mehrmals geladen haben (jeweils mit einem anderen ClassLoader). Diese Instanzen sind dann Inkompatibel zueinander... Hier muss man sicherstellen, dass die anderen ClassLoader den selben Parent-ClassLoader (mit zugriff zu den gemeinsamen Klassen ) verwenden.

Immer wenn augenscheinlich passende Type-Casts fehlschlagen ( object of type de.tutorials.Foo cannot be cast do de.tutorials.Foo) sind meistens mehrere Versionen einer Klasse daran schuld.

schau mal hier:
http://www.tutorials.de/forum/java/310207-eine-art-plugin-system-2.html
http://www.tutorials.de/forum/java/292847-urlclassloader-bringt-fehler.html

Gruß Tom
 
Richtig. Nur ein voll qualifizierter Klassenname ist eindeutig. Das ist der Punkt. So Classloadergeschichten sehen auf den ersten Blick immer einfach aus, die Tücke liegt oft im Detail. Ich will dir nicht die Illusion nehmen, aber ich habe bisher kein selbstgeschriebenes Pluginframework (das dynamisch Klassen nachlädt) gesehen, was ich produktiv einsetzen würd. Warum sonst hat man sich für Plattformen wie OSGi jahrelang nen Kopf zerbrochen, wenn es einfach in ein paar Zeilen geht.

Gruß
Ollie
 
Aus gegebenem Anlass:

It is essential to grasp that any Java type, such as a class or interface, must be loaded by a class loader before it is available at runtime. A runtime type is defined by the combination of the type's fully qualified class name and the class loader that defined the type. If the same fully qualified class name is defined by two distinct class loaders, then this produces two incompatible runtime types. This incompatibility causes runtime errors if the two types come into "contact". For example, attempting to cast one of these types to the other will result in a class cast exception.

Wenn auch in einem etwas anderen Kontext: http://blog.springsource.com/2008/10/20/understanding-the-osgi-uses-directive/

REINHAUN!
 
Zurück