Jar Dateien in Classpath laden ab JDK 9+

lam_tr

Top Contributor
Hallo zusammen,

kennt jemand eine Lösung wie ich Jar Dateien in den Classpath laden kann?
Ich habe in Java 8 immer gut mit den folgenden Code mein Ziel erreicht.
Java:
URLClassLoader sysloader = (URLClassLoader) ClassLoader.getSystemClassLoader();
Method method = URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{URL.class});
method.invoke(sysloader, new Object[]{file.toURI().toURL()});

Ab Java 9 ist es nicht mehr möglich. Ich habe hier eine Lösung gefunden https://stackoverflow.com/questions/48041764/add-jar-to-classpath-at-runtime-under-java-9 womit ich über einen Agenten hinzufügen kann. Ich muss den Agenten aber in MANIFEST.MF eintragen, was nicht möglich ist.

Gibts da noch andere Wege?

Viele Grüße
lam_tr
 

Robert Zenz

Top Contributor
Wenn ich mich richtig erinnere, ist "addURL" "protected", also du kannst "URLClassLoaser" erweitern und die Methode einfach mit einer "public" ueberschreiben. So wie hier im DynamicClassLoader.

Implikationen betreffend Multi-Threading und aehnliches weisz ich aber gerade nicht, musst du testen.

Also du musst dann natuerlich die Applikation mit dem ClassLoader laden.
 

lam_tr

Top Contributor
Wenn ich mich richtig erinnere, ist "addURL" "protected", also du kannst "URLClassLoaser" erweitern und die Methode einfach mit einer "public" ueberschreiben. So wie hier im DynamicClassLoader.

Implikationen betreffend Multi-Threading und aehnliches weisz ich aber gerade nicht, musst du testen.

Also du musst dann natuerlich die Applikation mit dem ClassLoader laden.
Ja genau hier der vollständige Code den ich bis einschließlich Java 8 benutzen kann
Java:
    @Override
    public void addPluginToClassPath(File jar) {
        // Get the ClassLoader class
        ClassLoader cl = ClassLoader.getSystemClassLoader();
        Class<?> clazz = cl.getClass();

        // Get the protected addURL method from the parent URLClassLoader class
        try {
            Method method = clazz.getSuperclass().getDeclaredMethod("addURL", new Class[] { URL.class });
            // Run projected addURL method to add JAR to classpath
            method.setAccessible(true);
            method.invoke(cl, new Object[] { jar.toURI().toURL() });
        } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
                | InvocationTargetException | MalformedURLException e) {
            LOGGER.error("Failed to add module " + jar.getName() + " to classpath", e);
        }
    }

Leider funktioniert das nicht für Java 9+.

Übrigens wenn ich im Java 16 das ausführe, bekomme ich diese Fehlermeldung
Java:
java.lang.NoSuchMethodException: jdk.internal.loader.BuiltinClassLoader.addURL(java.net.URL)
    at java.base/java.lang.Class.getDeclaredMethod(Class.java:2613)
 
Zuletzt bearbeitet:

mrBrown

Super-Moderator
Mitarbeiter
Der übliche Weg wäre ein eigener ClassLoader für das Plugin, statt die Classen in den SystemClassLoader zu laden. Spricht da bei dir irgendwas gegen?
 

lam_tr

Top Contributor
Der übliche Weg wäre ein eigener ClassLoader für das Plugin, statt die Classen in den SystemClassLoader zu laden. Spricht da bei dir irgendwas gegen?
Dann müsste ich jedes mal wenn ich per Reflections die Klasse instanziiere, zuerst mal schauen welchen ClassLoader zu welchem Plugin gehört und dann den richtigen ClassLoader mein Class.forName mitgeben oder?

Nachtrag:
Theoretisch könnte man es doch so wurschteln oder? Anstatt der addUrl kann ich appendClassPath machen.
Java:
    @Override
    public void addPluginToClassPath(File jar) {
        // Get the ClassLoader class
        ClassLoader cl = ClassLoader.getSystemClassLoader();
        Class<?> clazz = cl.getClass();

        // Get the protected addURL method from the parent URLClassLoader class
        try {
            Method method = clazz.getSuperclass().getDeclaredMethod("appendClassPath", new Class[] { String.class });
            // Run projected addURL method to add JAR to classpath
            method.setAccessible(true);
            method.invoke(cl, new Object[] { jar.toURI().toURL().toExternalForm() });
        } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
                | InvocationTargetException | MalformedURLException e) {
            LOGGER.error("Failed to add module " + jar.getName() + " to classpath", e);
        }

Allerdings bekomme ich diese Fehlermeldung
Java:
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make void jdk.internal.loader.BuiltinClassLoader.appendClassPath(java.lang.String) accessible: module java.base does not "opens jdk.internal.loader" to unnamed module
 
Zuletzt bearbeitet:

mrBrown

Super-Moderator
Mitarbeiter
Dann müsste ich jedes mal wenn ich per Reflections die Klasse instanziiere, zuerst mal schauen welchen ClassLoader zu welchem Plugin gehört und dann den richtigen ClassLoader mein Class.forName mitgeben oder?
Ja, aber üblicherweise klappt das völlig problemlos. So ein Class.forName was völlig ohne Kontext irgendwo aufgerufen wird, gibt's ja eher selten?
Schon den Klassennamen muss man ja irgendwoher bekommen, und darüber hat man doch meist den Bezug zum Plugin und damit dann auch zum ClassLoader. Im Idealfall hat man ja nicht mal ein Class.forName, sondern löst das über die vorhandenen Mechanismen wie zB ServiceLoader.


Als Bonus bekommt man halt saubere Trennung zwischen den Plugins.
 

lam_tr

Top Contributor
Ja, aber üblicherweise klappt das völlig problemlos. So ein Class.forName was völlig ohne Kontext irgendwo aufgerufen wird, gibt's ja eher selten?
Schon den Klassennamen muss man ja irgendwoher bekommen, und darüber hat man doch meist den Bezug zum Plugin und damit dann auch zum ClassLoader. Im Idealfall hat man ja nicht mal ein Class.forName, sondern löst das über die vorhandenen Mechanismen wie zB ServiceLoader.


Als Bonus bekommt man halt saubere Trennung zwischen den Plugins.
Vieleicht ist mein Ansatz auch nicht so gut, aber ich hole die Klassennamen aus einer XML Datei und die werden dann sozusagen zur Laufzeit geladen. Bevor das geschieht, werden alle bnötigten Dependencies in das Classpath hinzugefügt.
 

mrBrown

Super-Moderator
Mitarbeiter
Vieleicht ist mein Ansatz auch nicht so gut, aber ich hole die Klassennamen aus einer XML Datei und die werden dann sozusagen zur Laufzeit geladen. Bevor das geschieht, werden alle bnötigten Dependencies in das Classpath hinzugefügt.

Das ist auch ein völlig üblicher Ansatz, macht zB IntelliJ intern genauso. Aber die XML-Datei ist doch vermutlich irgendwie einem Plugin zugeordnet und fällt nicht völlig aus der Luft?

Und da du Dependencies erwähnst: bei deinem Ansatz sind die Dependencies aller Plugins gemischt, das will man potentiell ja auch nicht, weil die uU inkompatibel sind.


Was btw auch möglich ist: einen Allgemeinen Plugin-Classloader, und der delegiert intern an einen ClassLoader pro Plugin. Du musst dann weiterhin nicht wissen, welches Plugin du grad benutzt, sondern sprichst die über den allgemeinen an – hast aber trotzdem die saubere Trennung zwischen denen.
 

lam_tr

Top Contributor
Das ist auch ein völlig üblicher Ansatz, macht zB IntelliJ intern genauso. Aber die XML-Datei ist doch vermutlich irgendwie einem Plugin zugeordnet und fällt nicht völlig aus der Luft?

Und da du Dependencies erwähnst: bei deinem Ansatz sind die Dependencies aller Plugins gemischt, das will man potentiell ja auch nicht, weil die uU inkompatibel sind.


Was btw auch möglich ist: einen Allgemeinen Plugin-Classloader, und der delegiert intern an einen ClassLoader pro Plugin. Du musst dann weiterhin nicht wissen, welches Plugin du grad benutzt, sondern sprichst die über den allgemeinen an – hast aber trotzdem die saubere Trennung zwischen denen.
Ja das ist richtig, zu jedem Plugin gibt es eine sogenannte plugin.xml wo die ganzen Services registiert sind.

Der Ansatz mit Plugin Classloader hört sich gut an. Allerdings weiß ich noch nicht genau was damit gemeint ist für die Umsetzung. Soll ich eine Klasse PluginAClassLoader der von ClassLoader erbt anlegen. Und von außerhalb soll man sich an die Klasse bedienen für die Erstellung der Instanzen?

Wie komme ich von Main Projekt auf die ganzen PluginClassLoaders? oder soll an der Stelle die PluginClassLoader auch in der plugin.xml definiert werden?
 

mrBrown

Super-Moderator
Mitarbeiter
Allerdings weiß ich noch nicht genau was damit gemeint ist für die Umsetzung. Soll ich eine Klasse PluginAClassLoader der von ClassLoader erbt anlegen.
Nein, nicht spezifisch pro Plugin sondern nur einen PluginClassLoader, der wird dann für jedes Plugin instanziiert mit den Dependencies für das entsprechenden Plugin.

Wie komme ich von Main Projekt auf die ganzen PluginClassLoaders? oder soll an der Stelle die PluginClassLoader auch in der plugin.xml definiert werden?

Irgendwo findest du doch alle Plugins raus, die existieren? Wenn du dann das Plugin "lädst", erstellst du einen PluginClassLoader für das Plugin und merkst dir den irgendwo. Alle Klassen für das Plugin werden dann immer über den ClassLoader geladen.
 

lam_tr

Top Contributor
Nein, nicht spezifisch pro Plugin sondern nur einen PluginClassLoader, der wird dann für jedes Plugin instanziiert mit den Dependencies für das entsprechenden Plugin.



Irgendwo findest du doch alle Plugins raus, die existieren? Wenn du dann das Plugin "lädst", erstellst du einen PluginClassLoader für das Plugin und merkst dir den irgendwo. Alle Klassen für das Plugin werden dann immer über den ClassLoader geladen.
Die Idee war schon ganz cool, aber mir ist gerade bei der Umsetzung erst aufgefallen, dass in der plugin.xml eine Referenzierung auf ein anderes plugin gibt. D.h. über den Plugin ClassLoader kann es so auch nicht gehen.

Gibt es keinen Weg gleich alle jars in Classpath zu machen wie vor Java 9?

Okay alternativ, kann ich alle Jars in den Plugin ClassLoader stopfen und alle Instanzen über ihn instanzieren. Nicht so schön, aber möglich.
 
Zuletzt bearbeitet:

mrBrown

Super-Moderator
Mitarbeiter
Die Idee war schon ganz cool, aber mir ist gerade bei der Umsetzung erst aufgefallen, dass in der plugin.xml eine Referenzierung auf ein anderes plugin gibt. D.h. über den Plugin ClassLoader kann es so auch nicht gehen.
Das geht trotzdem problemlos, das wird uU minimal komplexer, weil man ein bisschen aufpassen muss, was an den parent-classloader delegiert wird, und was man im eigenen sucht, aber möglich ist das.

Gibt es keinen Weg gleich alle jars in Classpath zu machen wie vor Java 9?
Spätestens mit 16 & 17 gibt’s dann die nächsten Probleme.

Okay alternativ, kann ich alle Jars in den Plugin ClassLoader stopfen und alle Instanzen über ihn instanzieren. Nicht so schön, aber möglich.
Geht, ist aber eben unschön. Saubere Trennung und saubere Konzepte für Abhängigkeiten sind deutlich besser.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
Thomasneuling Java Jar datei erstellen, von Projekt, dass auch Javafx Dateien, FXML Dateien und CSS Dateien, sowie Bilder enthält? Allgemeine Java-Themen 14
G Dateien lesen Allgemeine Java-Themen 3
OnDemand Unterschiedliche jar Dateien zusammen führen Allgemeine Java-Themen 8
A Sicheres Löschen von Dateien Allgemeine Java-Themen 7
O git ignore für Intellji braucht es die .idea Dateien? Allgemeine Java-Themen 8
Master3000 Dateien zwischen verschiedenen Netzwerken senden Allgemeine Java-Themen 17
d.lumpi JDA eclipse dateien versenden Allgemeine Java-Themen 4
O Produziert das Tool "jpackage" (ab JDK 14) .exe Dateien, die auf einer Zielumgebung ohne JRE lauffähig sind ?` Allgemeine Java-Themen 7
O Wie kann ich in Apache POI (Excel Dateien schreiben) Datumszellen in Excel erzeugen Allgemeine Java-Themen 6
T Meine Frage lautet wie ich 2 CSV Dateien miteinander in Java verbinde und Spalten die zueinander gehören durch den gleichen Key zusammen ausgebe? Allgemeine Java-Themen 5
L Dateien richtig auslesen Allgemeine Java-Themen 6
L Eclipse Runnable Jar mit Dateien Allgemeine Java-Themen 8
W Server-Thread schreibt nicht alle Dateien Allgemeine Java-Themen 6
MiMa Logging mit log4j2 in verschiedene Dateien? Allgemeine Java-Themen 22
I Klassen aus Jar-Dateien aus anderem Ordner laden Allgemeine Java-Themen 3
O jar und EXE Dateien, Pfade zur Laufzeit Allgemeine Java-Themen 1
W Dateien werden nicht gelöscht - warum? Allgemeine Java-Themen 12
B Dateien / Bilder von "webapp" Ordner bekommen? Allgemeine Java-Themen 1
P Erste Schritte Dateien löschen Allgemeine Java-Themen 4
H Erste Schritte Ausführbare Dateien lassen sich nicht starten Allgemeine Java-Themen 5
I Java als exe veröffentlichen inkl. kompletter Dateien Allgemeine Java-Themen 4
M Drucken von Dateien Allgemeine Java-Themen 10
J jar Dateien unter Windows 7 mit spezifischer jdk öffnen Allgemeine Java-Themen 2
I Laden von Informationen aus Dateien: Austauschbarkeit: 2 Dateien sinnvoll? Allgemeine Java-Themen 2
N Temporäre Dateien Allgemeine Java-Themen 3
Bluedaishi Druck Probleme mit PDF dateien Allgemeine Java-Themen 4
M Dateien schneller kopieren Allgemeine Java-Themen 1
M Dateien nach kopieren vergleichen Allgemeine Java-Themen 9
Arif Input/Output Dateien im Jar-Programm speichern Allgemeine Java-Themen 12
D Collections.sort funktioniert nicht in exportierten .class Dateien Allgemeine Java-Themen 10
K Große JSON-Dateien schnell und effizient verarbeiten Allgemeine Java-Themen 16
J Programm zum Download von CSV-Dateien Allgemeine Java-Themen 4
V Eclipse .class Dateien Allgemeine Java-Themen 9
B Download von dateien Allgemeine Java-Themen 2
K Nicht alle class-Dateien im JRE? Allgemeine Java-Themen 2
MiMa Log4j in Dateien mit eigenem Namen schreiben Allgemeine Java-Themen 3
D Kopieren von Dateien aus einem Ordner in einen anderen Allgemeine Java-Themen 6
C Dateien in Jar aufrufen Allgemeine Java-Themen 14
X NetBeans Bilder und andere Dateien ins .jar schreiben und wieder aus .jar lesen Allgemeine Java-Themen 6
JavaWolf165 Externe .jar-Dateien in .jar-Datei intigrieren Allgemeine Java-Themen 0
X Dateien für Benutzer Sperren Allgemeine Java-Themen 4
D Dateien aus den Internet herunterladen Allgemeine Java-Themen 6
L Methoden Dateien älter als 30 Tage? Allgemeine Java-Themen 11
J .exe Dateien werden nicht gestartet obwohl Pfad richtig Allgemeine Java-Themen 6
RalleYTN Classpath Native Dateien(DLL, SO, JNILIB) Allgemeine Java-Themen 2
J Java .jar Dateien zusammenführen Allgemeine Java-Themen 1
L Best Practice Log Dateien analysieren und eventuell passende Daten am Chart darstellen Allgemeine Java-Themen 1
F Platzsparende Alternative zu .txt-Dateien Allgemeine Java-Themen 12
X Dateien von der Jar zum Ordner kopieren. Allgemeine Java-Themen 4
Ananaskirsche Input/Output Dateien im Ordner Allgemeine Java-Themen 8
A Input/Output Liste der Dateien in einem Ordner in einer Jar Datei erhalten Allgemeine Java-Themen 11
X Herunterladen von Dateien aus dem Internet Allgemeine Java-Themen 2
V Input/Output Sound Dateien aus Jar laden Allgemeine Java-Themen 18
M Dateien aus einem Verzeichnis auf einem Server auflisten Allgemeine Java-Themen 5
H PDFBox akzeptiert Dateien nicht Allgemeine Java-Themen 1
B Java - einlesen von Dateien und herausschneiden von XML Dokumenten Allgemeine Java-Themen 5
A Input/Output Spätes Schreiben von Dateien der JVM Allgemeine Java-Themen 3
M Zwei unterschiedliche JAR Dateien mit ANT erstellen Allgemeine Java-Themen 8
Thallius Dateien Zippen und wieder heraus lesen? Allgemeine Java-Themen 4
T Dateien zur Laufzeit in Java-Programm packen? Allgemeine Java-Themen 3
Maxim6394 Jar Dateien starten nicht Allgemeine Java-Themen 7
U Eclipse Java Programm beschädigt .tar.gz dateien beim Entpacken Allgemeine Java-Themen 7
GUI-Programmer Mp3 Dateien bearbeiten und speichern Allgemeine Java-Themen 3
S Exklusive Sperre auf Dateien: FileChannel, FileLock Allgemeine Java-Themen 0
Bluedaishi Dateien löschen die älter als das aktuelle Datum sind Allgemeine Java-Themen 9
OnDemand Dateien einlesen und vergleichen Allgemeine Java-Themen 1
T Ordner samt Dateien kopieren Allgemeine Java-Themen 11
R Importieren von Txt-Dateien in AbstractTableModel Allgemeine Java-Themen 0
C Dateien komprimieren und verschlüsseln Allgemeine Java-Themen 3
F Eclipse Eclipse kompiliert nicht mehr die aktuellen Dateien Allgemeine Java-Themen 2
R Java Dateien "verschlüsseln" Allgemeine Java-Themen 2
L Passwortgeschützte Dateien Allgemeine Java-Themen 6
A Datentypen Dateien umbenennen mit Dateiendungen - Dateiendungen ausgeben Allgemeine Java-Themen 2
L Reparieren beschädigter PDF Dateien Allgemeine Java-Themen 3
F Dateien ins Array lagern und Optionen zur Auswahl, Allgemeine Java-Themen 5
J XML Dateien vergleichen Allgemeine Java-Themen 9
B Umbenennen von Dateien Allgemeine Java-Themen 2
B Erste Schritte Plugin erkennen und Class Dateien anzeigen lassen Allgemeine Java-Themen 3
W Best Practice Dateien parsen Allgemeine Java-Themen 3
B Dateien verschwinden aus bin Ordner?! Allgemeine Java-Themen 5
B Dateien prüfen auf Gleichheit Allgemeine Java-Themen 5
M Java Dateien verschieben Allgemeine Java-Themen 2
R Wav-Dateien wiederholt abspielen Allgemeine Java-Themen 2
L Methoden Verarbeitung von Größen Dateien Allgemeine Java-Themen 9
B Alt-Griechisch Zeichen in Dateien Allgemeine Java-Themen 2
M JAR Dateien nur mit Compiler Level 1.6 ausführbar Allgemeine Java-Themen 8
E Zugriff auf Dateien im Filesystem überwachen Allgemeine Java-Themen 5
G .jar Dateien lassen sich nicht mehr öffnen Allgemeine Java-Themen 2
M Datentypen Jar-Dateien öffnen nicht mit Java Allgemeine Java-Themen 4
C Mit Java PDF Dateien bearbeiten. Allgemeine Java-Themen 2
B Input/Output .java-Dateien auslesen Allgemeine Java-Themen 17
B Methoden Alle Methoden und Variablen aus Java-Dateien auslesen. Allgemeine Java-Themen 7
E Vorschläge, effizientes Hashing von Dateien für vergleich Allgemeine Java-Themen 7
W Vergleich eines Datenträgers auf neue Dateien Allgemeine Java-Themen 14
C Java-Dateien in einheitlichen Zeichensatz umwandeln Allgemeine Java-Themen 10
E Dateien aus / im JAR Allgemeine Java-Themen 2
K LibreOffice Tabelle Dateien im Format .ods bearbeiten Allgemeine Java-Themen 2
L Input/Output Dateien erstellen, wenn ein JAR ausgeführt wird Allgemeine Java-Themen 13
L Generieren Zufallsdaten aus CSV dateien Allgemeine Java-Themen 11
G Namensgebung der Dateien von FileHandler Allgemeine Java-Themen 4

Ähnliche Java Themen

Neue Themen


Oben