Dynamisch Klasse aus *.jar laden - Frage

M_Kay

Mitglied
Hi,

ich habe vor aus einem bestehenden *.jar eine Klasse zur Lauzeit nachzuladen, um Funktionen daraus aufzurufen. Also so eine Art PlugIn, da man mein Programm mit einem *.jar mit neuen Funktionen erweitern kann.

Ich habe schon hier und da gesucht und was gefunden und bin hier angelangt (aus einem Forum ein wenig abgewandelt):
Code:
        File fJar = new File(JarFile); //Path of jar file
        URL url = null;
        try {
            //get Jar-Url
            url = fJar.toURL();
            URLClassLoader urlcl = new URLClassLoader(new URL[] {url});
            String strPackage = "abc.moep"; //Package/Class-Name
            Class clazz = Class.forName(strPackage, true, urlcl);
         
            //load Constructor (string, string)
            Constructor cons = null;
            cons = clazz.getConstructor(String.class, String.class);
            Object instance = cons.newInstance("", ""); //call constructor
            return instance;
        }
        catch(Exception ex) {
            ex.printStackTrace();
            return null;
        }
Hier wird also, wenn alles erfolgreich war eine Instanz als Object zurückgeliefert, mit dem ich ja eigentlich die Funktionen der Klasse aufrufen könnte.
Doch irgendwie bin ich z.Z. zu blöd oder habe eine Blockade :D

Ich kann ja jetzt nicht einfach "instance.Methodenname" machen, da ein Objekt vom Typ Object meine Methoden ja nicht kennt. Wie kann ich diese trotzdem aurufen?

Vielen Dank schonmal für eure Hilfe :)
Gruss
M_Kay
 
Hallo,

du hast doch sicher ein Interface oder eine abstrakte Basisklasse, von der jede Plugin-Klasse erbt? Dann reicht ein einfacher Typecast darauf, damit du auf die spezifischen Methoden zugreifen kannst.

Grüße,
Matthias
 
Ne, bisher nicht, hatte aber diesbezüglich schon überlegt :)
Also muss ich eine abstrakte Klasse/Interface in mein Main-Jar packen, und das PlugIn-Jar von diesem erben lassen?

Dann muss ich ja wiederum im PlugIn-Jar in der Klasse ein Import von der abstrakten Klasse (aus dem Main) machen.

Wie mache ich das am besten? Ich muss ja das jar von einem Verzeichnis drüber importieren (Plugins liegen in einem Unterorder). Das wäre ja das selbe wie ich es bereits mache nur in Umgekehrter Reihenfolge, oder? :)

Ich habe bestimmt gerade total den Denkfehler :D
Mein Programm selbst und damit dann auch das Interface/die abstrakte Klasse liegen später in einem Main.jar und die PlugIns nicht in diesem jar, sondern in einem Unterorder.

- Hilfe :) -

EDIT:
Ich habe mit Hilfe von http://www.javangelist.de/space/Plugin jetzt etwas hinbekommen :)
Eine Frage bleibt jetzt aber noch: Ich muss dem PlugIn-Entwickler das Interface fürs PlugIn oder die Abstrakte Klasse zur Verfügung stellen, damit der anständig arbeiten kann, richtig?

Und noch was: Wie kann ich erkennen, ob eine Funktion existiert?
Eigentlich soll der Plug-In-Entwickler ja anhand einer abstrakten Klasse coden und sollte dann sehen, welche Funktionen er implementieren muss.
Aber was ist, wenn derjenige eine alte Version der abstrakten Klasse oder des interfaces nutzt? Wie kann ich dann prüfen, ob die Klasse eine bestimmte Methode enthält?
 
Zuletzt bearbeitet:
Eine Frage bleibt jetzt aber noch: Ich muss dem PlugIn-Entwickler das Interface fürs PlugIn oder die Abstrakte Klasse zur Verfügung stellen, damit der anständig arbeiten kann, richtig?
Genau das ist richtig - ich würde mir ein eigenes Jar Package erzeugen wo nur Interfaces und abstrakte Methoden etc. drinnen sind.
Nur diese Klassen eben, die der Plugin entwickler benötigt.
Dieses Jar musst du dann im Hauptprogramm dazulinken und der Plugin entwickler muss das auch.

Und noch was: Wie kann ich erkennen, ob eine Funktion existiert?
Eigentlich soll der Plug-In-Entwickler ja anhand einer abstrakten Klasse coden und sollte dann sehen, welche Funktionen er implementieren muss.
Aber was ist, wenn derjenige eine alte Version der abstrakten Klasse oder des interfaces nutzt? Wie kann ich dann prüfen, ob die Klasse eine bestimmte Methode enthält?
Es gibt eine Möglichkeit über Reflection (siehe objekt.getClass()) abzufragen, welche Methoden ein Objekt besitzt).
Jedoch ist das in deinem Fall unnötig, denn wenn du es so machst, dass beide (Plugin Entwickler und Hauptprogramm) die selben "Plugin SDK Jar" linken müssen, gibt dein Java Programm sowiso einen Fehler wenn diese Versionen unterschiedlich sind. Die Java Runtime erkennt, dass die beiden Klassen nicht die selben sind und wirft eine Exception.

Lg, Yanick
 
Erstmal thx for reply.

Genau das ist richtig - ich würde mir ein eigenes Jar Package erzeugen wo nur Interfaces und abstrakte Methoden etc. drinnen sind.
Nur diese Klassen eben, die der Plugin entwickler benötigt.
Dieses Jar musst du dann im Hauptprogramm dazulinken und der Plugin entwickler muss das auch.
Okay, und wo kommt das jar mit dem interface dann hin, ins Main- oder PlugIn-Verzeichnis? Bei einem von beiden (PlugIn oder Main-Jar) muss ich ja das Paket wieder dynamisch laden, wie ich es mit den PlugIns mache, oder geht das ebenfalls über einen einfach import bei beiden jars?

Es gibt eine Möglichkeit über Reflection (siehe objekt.getClass()) abzufragen, welche Methoden ein Objekt besitzt).
Jedoch ist das in deinem Fall unnötig, denn wenn du es so machst, dass beide (Plugin Entwickler und Hauptprogramm) die selben "Plugin SDK Jar" linken müssen, gibt dein Java Programm sowiso einen Fehler wenn diese Versionen unterschiedlich sind. Die Java Runtime erkennt, dass die beiden Klassen nicht die selben sind und wirft eine Exception.
Bisher hatte er nicht gemeckert, wenn z.B. die Parameter der Funktionen unterschiedlich sind. Akllerdings habe ich bisher auch kein zentrales "PlugIn SDK Jar" (s.o.).

Wenn das interface jedoch in einem externen jar liegt, dann kann es ja problemlos ausgetauscht werden. Dann tauchen plötzlich PlugIns in der Liste auf, die gar nicht funktionieren :)

Edit:
Bei diesem Code gibt er mir die folgende Warning aus:
Code:
	    	Constructor cons = null;
	    	cons = clazz.getConstructor((Class)null); //<-- hier Fehler
Type safety: The method getConstructor(Class...) belongs to the raw type Class. References to generic type Class<T> should be parameterized
Wie bekomme ich das weg? :)
 
Zuletzt bearbeitet:
Wenn Du einen parameterlosen Constructor hast kann du einen Instanz auf folgende Weisen erzeugen

1:
Java:
Object o = clazz.newInstance();
oder 2:
Java:
Constructor<Object> constructor = clazz.getConstructor(new Class[]{});
Object o = constructor.newInstance(new Object(){});
oder 3, Du nimmst ein Interface dazu
Java:
Constructor<Serializable> constructor = clazz.getConstructor(new Class[]{});
Serializable o = constructor.newInstance(new Object(){});
 
Hi,

erstmal danke für deine Antwort.
Mit dem Code
Code:
Object o = clazz.newInstance();
funktioniert alles einwandfrei.

Trotzdem interessiert mich, warum ich mit den beiden anderen Lösungen nicht klarkomme :D

Bei dem Code
Code:
Constructor<Object> cons = clazz.getConstructor(new Class[]{});
erhalte ich folgende Meldungen:
Type safety: The expression of type Constructor needs unchecked conversion to conform to Constructor<Object>

Type safety: The method getConstructor(Class...) belongs to the raw type Class. References to generic type Class<T> should be parameterized

Was ist da noch "falsch"?
 
Trotzdem interessiert mich, warum ich mit den beiden anderen Lösungen nicht klarkomme :D

Bei dem Code
Code:
Constructor<Object> cons = clazz.getConstructor(new Class[]{});
erhalte ich folgende Meldungen:


Was ist da noch "falsch"?

Das würde mich auch interessieren. Hast Du den Codeausschnitt von oben benutzt? Ich verwende Java 6, da tut's wie es soll.

Gruss
 
Zurück