PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Java: Klassen finden, die ein bestimmtes Interface implementieren


SavageX
2007-03-05, 11:54:18
Hallo,

ich stehe hier vor dem Problem, dass ich zur Laufzeit Klassen finden muss ("Plugin-System"), die ein vorgegebnes Interface mit Leben füllen.

Hierbei gilt:

- ich weiß nicht, zu welchen Packages die Klassen gehören, die dürfen überall im Namespace herumfliegen
- ich weiß nicht, wo die physikalisch herumliegen (im Dateisystem, in welchen JARs etc.) (deshalb kann ich nicht einfach ein Dateisystem/ein JAR durchsuchen)

Gibt es irgendwie ein Möglichkeit, eine Auflistung aller Klassen zu bekommen, die gerade im Classpath liegen?

Senior Sanchez
2007-03-05, 11:58:12
Soweit ich weiß nicht, aber warum benutzte nicht einfach eine config-datei (z.B. xml) bei der die zuverwendene Klasse mit ihrem vollen Klassennamen (also auch mit package-bezeichnung) erwähnt ist?

Ich meine, das macht Java ja im Grunde genauso bei der Manifest Datei oder bei Webstart oder bei Applets etc.

Monger
2007-03-05, 12:03:14
Du kannst natürlich ganz brutal das gesamte Dateisystem (bzw. ein bestimmtes Unterverzeichnis) durchsuchen, und alle .class Dateien mal probeweise in den Classloader schieben, und mal probieren ob es passt.

Aber insgesamt hört sich der Ansatz ziemlich hässlich an. Alleine, dass Plugins in beliebigen Verzeichnissen rumliegen dürfen, halte ich für öh... designmäßig problematisch.

Senior Sanchez
2007-03-05, 12:18:36
Du kannst natürlich ganz brutal das gesamte Dateisystem (bzw. ein bestimmtes Unterverzeichnis) durchsuchen, und alle .class Dateien mal probeweise in den Classloader schieben, und mal probieren ob es passt.

Aber insgesamt hört sich der Ansatz ziemlich hässlich an. Alleine, dass Plugins in beliebigen Verzeichnissen rumliegen dürfen, halte ich für öh... designmäßig problematisch.

Sehe ich genauso.

Zumal, SavageX, wenn ich das richtig verstehe entwickelt ihr ja das Plugin-System selber, also habt ihr dabei doch gewisse Freiheiten und könnt ganz klar sagen: So muss es sein!

Man muss nicht immer für jede mögliche, abwegige Konstellation eine Lösung parat haben, bin ich der Meinung. Der User kann ruhig auch etwas Verantwortung an die Hand bekommen.

SavageX
2007-03-05, 12:21:37
Okay, sieht so aus, als müsste ich dann all JAR Dateien in einem bestimmten Unterverzeichnis durchsuchen (dann Klasse laden, gucken ob sie passt etc.).

Vielen Dank!

SavageX
2007-03-05, 12:28:11
Zumal, SavageX, wenn ich das richtig verstehe entwickelt ihr ja das Plugin-System selber, also habt ihr dabei doch gewisse Freiheiten und könnt ganz klar sagen: So muss es sein!


Na, das Ding ist Teil meiner Diplomarbeit und der Betreuer hat nur sehr lasch spezifiert, dass ich mich nach "passenden" Klassen umgucken soll, um dann dynamisch was wunderhübsches mit denen anzufangen. Deshalb suchte ich erstmal nach einem möglichst generischem Weg, der absolut benutzersicher ist.

Gut, jetzt ziehe ich die Zügel hat heftig ( :wink: ) an und fordere das Vorhandensein in einem bestimmten Verzeichnis. Ist vielleicht tatsächlich auch sinnig, um zu Verhindern, dass Sachen, die noch irgendwo vergessen worden sind, aus meiner Applikation Gulasch machen.

darph
2007-03-05, 12:30:45
Naja, du könntest sagen, daß ein Plugin nur verwertet wird, wenn es sich mit einer bestimmten Methode irgendwo registriert (muß dann halt kein Interface implementieren sondern erweitert eine abstrakte Klasse, wo diese Registrierung schon vorbereitet ist). Dann kannst du mit instanceOf schauen, welche Art von Plugin es jetzt ist, jenachdem, was genau es implementiert.

SavageX
2007-03-05, 12:40:12
Naja, du könntest sagen, daß ein Plugin nur verwertet wird, wenn es sich mit einer bestimmten Methode irgendwo registriert (muß dann halt kein Interface implementieren sondern erweitert eine abstrakte Klasse, wo diese Registrierung schon vorbereitet ist). Dann kannst du mit instanceOf schauen, welche Art von Plugin es jetzt ist, jenachdem, was genau es implementiert.

Nun, wenn sich die Plugins selbst registrieren würden, wäre das natürlich super supili supileinchen. Mir ist allerdings ad-hoc nicht klar, wer denn deren Registrierungsmethode anstößt... steh ich mal wieder im Wald und seh die ganze Photosynthese um mich herum nicht?

Senior Sanchez
2007-03-05, 12:46:01
Naja, du könntest sagen, daß ein Plugin nur verwertet wird, wenn es sich mit einer bestimmten Methode irgendwo registriert (muß dann halt kein Interface implementieren sondern erweitert eine abstrakte Klasse, wo diese Registrierung schon vorbereitet ist). Dann kannst du mit instanceOf schauen, welche Art von Plugin es jetzt ist, jenachdem, was genau es implementiert.

Die Plugins müssen dazu aber eben schonmal geladen sein und das ist ja erstmal das Problem: Die Klassen zu laden. Was danach passiert ist ja nicht weiter dramatisch.

@SavageX
Bestimmte Leute sagen gerne Dinge ganz lasch ;) Wie gesagt, verlange dass sie in einem bestimmten Verzeichnis liegen und verlange vom Pluginschreiber am besten noch eine Manifest-Datei oder dergleichen.

Monger
2007-03-05, 14:33:06
Nun, wenn sich die Plugins selbst registrieren würden, wäre das natürlich super supili supileinchen. Mir ist allerdings ad-hoc nicht klar, wer denn deren Registrierungsmethode anstößt... steh ich mal wieder im Wald und seh die ganze Photosynthese um mich herum nicht?
Im Endeffekt wäre das ein Job für einen Installer. Der sagt dann: "Hallo, ich bin ein neues Addon. Ich bestehe aus den und den Daten, und du findest mich hier ->"

Mir erscheint das logisch, denn zumindest das Plugin muss eigentlich wissen, zu welcher Art von Applikation es gehört. Dann ist es einfacher, wenn es sich aktiv meldet, als wenn man erst aufwendig danach suchen muss.

SavageX
2007-03-05, 15:01:14
Okay, danke für den vielen Input hier.

Nun, ich vermeide Installer wo immer möglich. Entpacken, läuft - so stell ich mir das vor.

Mal gucken, was ich mir zusammenbastele.

SavageX
2007-03-05, 17:54:37
Ich habe das jetzt mal derartig zusammengelötet. Damit gewinn ich zwar höchstens den Karl Ranseier Preis für besondere Codeverbrechen, aber es funktioniert (und ja, beim Umsetzen von JarEntry-Namen zu Klassenamen mache ich wohl redundante Ersetzungen... aber ich gehe lieber auf Nummer sicher).


// find classes implementing BusinessLearnerSIBInterface
SIBs = new Vector<Class>();

File plugindir = new File("plugins" + File.separator);

for(File f : plugindir.listFiles()) {
if(f.getAbsolutePath().endsWith(".jar")) {
try {
JarFile jf = new JarFile(f);

Enumeration<JarEntry> entries = jf.entries();

while(entries.hasMoreElements()) {
JarEntry e = entries.nextElement();

if(e.getName().endsWith(".class")) {

String classname = e.getName();
classname = classname.substring(0, classname.lastIndexOf("."));
classname = classname.replace(File.separator, ".");
classname = classname.replace("/", ".");
classname = classname.replace("\\", ".");

try {
Class cl = Class.forName(classname);
Class[] interfaces = cl.getInterfaces();

for(Class iface : interfaces)
if(iface.equals(BusinessLearnerSIBInterface.class))
SIBs.add(cl);
} catch(java.lang.ClassNotFoundException ex) {
} catch(java.lang.NoClassDefFoundError ex) {
} catch(java.lang.ExceptionInInitializerError ex) {}

}
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}

Köppchen
2007-03-06, 00:43:49
Wie wärs mit dem ServiceLoader API für diesen Zweck? Siehe auch http://java.sun.com/javase/6/docs/api/java/util/ServiceLoader.html

SavageX
2007-03-06, 13:10:46
Wie wärs mit dem ServiceLoader API für diesen Zweck? Siehe auch http://java.sun.com/javase/6/docs/api/java/util/ServiceLoader.html

Ich bin auf Java 5 festgenagelt. Aber danke für den Tipp, das klingt eigentlich ganz lecker.