Kurze Zusammenfassung, Sie können entweder:
Fügen Sie die JavaFX-Module über --module-path
und --add-modules
wie in Josés Antwort ein.
ODER
Wenn Sie Ihrem Projekt JavaFX-Bibliotheken hinzugefügt haben (entweder manuell oder über den Maven / Gradle-Import), fügen Sie die module-info.java
Datei hinzu, die der in dieser Antwort angegebenen ähnelt. (Beachten Sie, dass diese Lösung Ihre App modular macht. Wenn Sie also andere Bibliotheken verwenden, müssen Sie auch Anweisungen hinzufügen, damit deren Module in der module-info.java
Datei enthalten sind.)
Diese Antwort ist eine Ergänzung zu Joses Antwort.
Die Situation ist folgende:
- Sie verwenden eine aktuelle Java-Version, z. B. 13.
- Sie haben eine JavaFX-Anwendung als Maven-Projekt.
- In Ihrem Maven-Projekt haben Sie das JavaFX-Plugin konfiguriert und die JavaFX-Abhängigkeiten gemäß der Antwort von Jose eingerichtet.
- Sie gehen zum Quellcode Ihrer Hauptklasse, der Application erweitert, klicken mit der rechten Maustaste darauf und versuchen, ihn auszuführen.
- Sie erhalten ein
IllegalAccessError
ein „unnamed Modul“ beteiligt , wenn sie versuchen , die App zu starten.
Auszug aus einem Stack-Trace, der IllegalAccessError
beim Versuch, eine JavaFX-App über Intellij Idea auszuführen, eine generiert:
Exception in Application start method
java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:567)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:464)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:363)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:567)
at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1051)
Caused by: java.lang.RuntimeException: Exception in Application start method
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:900)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:195)
at java.base/java.lang.Thread.run(Thread.java:830)
Caused by: java.lang.IllegalAccessError: class com.sun.javafx.fxml.FXMLLoaderHelper (in unnamed module @0x45069d0e) cannot access class com.sun.javafx.util.Utils (in module javafx.graphics) because module javafx.graphics does not export com.sun.javafx.util to unnamed module @0x45069d0e
at com.sun.javafx.fxml.FXMLLoaderHelper.<clinit>(FXMLLoaderHelper.java:38)
at javafx.fxml.FXMLLoader.<clinit>(FXMLLoader.java:2056)
at org.jewelsea.demo.javafx.springboot.Main.start(Main.java:13)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:846)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:455)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
Exception running application org.jewelsea.demo.javafx.springboot.Main
OK, jetzt steckst du irgendwie fest und hast keine Ahnung, was los ist.
Was tatsächlich passiert ist, ist Folgendes:
- Maven hat die JavaFX-Abhängigkeiten für Ihre Anwendung erfolgreich heruntergeladen, sodass Sie die Abhängigkeiten nicht separat herunterladen oder ein JavaFX-SDK oder eine Modulverteilung oder ähnliches installieren müssen.
- Idea hat die Module erfolgreich als Abhängigkeiten in Ihr Projekt importiert, sodass alles in Ordnung kompiliert und der gesamte Code vervollständigt wird und alles einwandfrei funktioniert.
Es scheint also, dass alles in Ordnung sein sollte. ABER, wenn Sie Ihre Anwendung ausführen, schlägt der Code in den JavaFX-Modulen fehl, wenn Sie versuchen, mithilfe von Reflection Instanzen Ihrer Anwendungsklasse (beim Aufrufen des Starts) und Ihrer FXML-Controller-Klassen (beim Laden von FXML) zu instanziieren. Ohne Hilfe kann diese Verwendung der Reflexion in einigen Fällen fehlschlagen und die Dunkelheit erzeugenIllegalAccessError
. Dies liegt an einer Sicherheitsfunktion des Java-Modulsystems, die es Code von anderen Modulen nicht erlaubt, Reflektion für Ihre Klassen zu verwenden, es sei denn, Sie erlauben dies ausdrücklich (und der JavaFX-Anwendungsstarter und FXMLLoader erfordern beide eine Reflektion in ihrer aktuellen Implementierung, damit sie funktionieren korrekt).
Hier kommen einige der anderen Antworten auf diese Frage module-info.java
ins Spiel.
Nehmen wir also an einem Crashkurs in Java-Modulen teil:
Der Schlüsselteil ist folgender:
4.9. Öffnet
Wenn wir die Reflektion privater Typen zulassen müssen, aber nicht möchten, dass unser gesamter Code verfügbar gemacht wird, können wir die opens-Direktive verwenden, um bestimmte Pakete verfügbar zu machen.
Aber denken Sie daran, dies wird das Paket für die ganze Welt öffnen. Stellen Sie also sicher, dass Sie genau das möchten:
module my.module { opens com.my.package; }
Vielleicht möchten Sie Ihr Paket nicht für die ganze Welt öffnen, dann können Sie Folgendes tun:
4.10. Öffnet… bis
Okay, Reflexion ist manchmal großartig, aber wir wollen immer noch so viel Sicherheit wie möglich durch Kapselung. Wir können unsere Pakete selektiv für eine vorab genehmigte Liste von Modulen öffnen, in diesem Fall mithilfe der Anweisung opens… to:
module my.module {öffnet com.my.package für moduleOne, moduleTwo usw.; }}
Am Ende erstellen Sie also eine src / main / java / module-info.java-Klasse, die folgendermaßen aussieht:
module org.jewelsea.demo.javafx.springboot {
requires javafx.fxml;
requires javafx.controls;
requires javafx.graphics;
opens org.jewelsea.demo.javafx.springboot to javafx.graphics,javafx.fxml;
}
Wobei org.jewelsea.demo.javafx.springboot
der Name des Pakets ist, das die Klassen JavaFX Application und JavaFX Controller enthält (ersetzen Sie diesen durch den entsprechenden Paketnamen für Ihre Anwendung). Dies teilt der Java-Laufzeit mit, dass es für Klassen in javafx.graphics
und javafx.fxml
in Ordnung ist, die Klassen in Ihrem org.jewelsea.demo.javafx.springboot
Paket zu reflektieren . Sobald dies erledigt ist und die Anwendung kompiliert und erneut ausgeführt wurde, funktionieren die Dinge einwandfrei und die IllegalAccessError
durch JavaFX generierte Verwendung von Reflection tritt nicht mehr auf.
Was aber, wenn Sie keine Datei module-info.java erstellen möchten?
Wenn Sie anstelle der Schaltfläche Ausführen in der oberen Symbolleiste der IDE Ihre Anwendungsklasse direkt ausführen möchten, gehen Sie stattdessen wie folgt vor:
- Ging zum Maven-Fenster an der Seite der IDE.
- Wählen Sie das Ziel des Javafx Maven Plugins
javafx.run
.
- Klicken Sie mit der rechten Maustaste darauf und wählen Sie entweder
Run Maven Build
oder Debug...
.
Dann wird die App ohne die module-info.java
Datei ausgeführt. Ich denke, das liegt daran, dass das Maven-Plugin intelligent genug ist, um dynamisch einige Einstellungen aufzunehmen, mit denen die App auch ohne module-info.java
Datei von den JavaFX-Klassen reflektiert werden kann, obwohl ich nicht weiß, wie dies erreicht wird.
Um diese Einstellung auf die Schaltfläche Ausführen in der oberen Symbolleiste zu übertragen, klicken Sie mit der rechten Maustaste auf das javafx.run
Maven-Ziel und wählen Sie die Option Create Run/Debug Configuration
für das Ziel. Dann können Sie einfach in der oberen Symbolleiste Ausführen auswählen, um das Maven-Ziel auszuführen.