# Dynamisch Klasse aus *.jar laden - Frage



## M_Kay (28. Juni 2007)

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):

```
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 

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


----------



## Matthias Reitinger (28. Juni 2007)

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


----------



## M_Kay (28. Juni 2007)

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 
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?


----------



## yan1 (29. Juni 2007)

M_Kay hat gesagt.:


> 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.



M_Kay hat gesagt.:


> 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


----------



## M_Kay (29. Juni 2007)

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:

```
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?


----------



## limago (30. Juni 2007)

Wenn Du einen parameterlosen Constructor hast kann du einen Instanz auf folgende Weisen erzeugen

1:

```
Object o = clazz.newInstance();
```
oder 2:

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

```
Constructor<Serializable> constructor = clazz.getConstructor(new Class[]{});
Serializable o = constructor.newInstance(new Object(){});
```


----------



## M_Kay (30. Juni 2007)

Hi,

erstmal danke für deine Antwort.
Mit dem Code

```
Object o = clazz.newInstance();
```
funktioniert alles einwandfrei.

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

Bei dem 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"?


----------



## Thomas Darimont (30. Juni 2007)

Hallo,



> Wenn Du einen parameterlosen Constructor hast kann du einen Instanz auf folgende Weisen erzeugen


...
da gibts noch ein paar Ausnahmen...:
Z.Bsp.:
http://www.tutorials.de/forum/java/269553-objekt-instanz-erzeugen-ohne-konstruktor-aufzurufen.html

Btw.:

```
Constructor<?> cons = clazz.getConstructor();
```
Sollte es tun...

Gruß Tom


----------



## limago (30. Juni 2007)

M_Kay hat gesagt.:


> Trotzdem interessiert mich, warum ich mit den beiden anderen Lösungen nicht klarkomme
> 
> Bei dem Code
> 
> ...



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

Gruss


----------



## M_Kay (30. Juni 2007)

Jo, Java 6 mit Eclipse 3.2.2.
Code ist der wie oben. Aber egal, dass andere funkotioniert ja


----------

