Szybkie podsumowanie, możesz:
Dołącz moduły JavaFX za pośrednictwem --module-path
i--add-modules
jak w odpowiedzi José.
LUB
Po dodaniu bibliotek JavaFX do projektu (ręcznie lub za pomocą importu maven / gradle) dodaj module-info.java
plik podobny do podanego w tej odpowiedzi. (Zwróć uwagę, że to rozwiązanie sprawia, że Twoja aplikacja jest modułowa, więc jeśli używasz innych bibliotek, będziesz musiał również dodać instrukcje, aby wymagać ich modułów w module-info.java
pliku).
Ta odpowiedź jest uzupełnieniem odpowiedzi Jose.
Sytuacja jest następująca:
- Używasz najnowszej wersji Java, np. 13.
- Masz aplikację JavaFX jako projekt Maven.
- W swoim projekcie Maven masz skonfigurowaną wtyczkę JavaFX i ustawienia zależności JavaFX zgodnie z odpowiedzią Jose.
- Wchodzisz do kodu źródłowego swojej głównej klasy, która rozszerza Application, klikasz go prawym przyciskiem myszy i próbujesz go uruchomić.
- Masz
IllegalAccessError
obejmujące moduł „nienazwany” podczas próby uruchomienia aplikacji.
Fragment śledzenia stosu generującego plik IllegalAccessError
podczas próby uruchomienia aplikacji JavaFX z Intellij Idea:
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, teraz utknęłaś i nie masz pojęcia, co się dzieje.
Co się właściwie wydarzyło, to:
- Maven pomyślnie pobrał zależności JavaFX dla Twojej aplikacji, więc nie musisz oddzielnie pobierać zależności ani instalować pakietu JavaFX SDK lub dystrybucji modułów ani niczego podobnego.
- Idea z powodzeniem zaimportowała moduły jako zależności do twojego projektu, więc wszystko kompiluje się dobrze, a zakończenie kodu i wszystko działa dobrze.
Więc wydaje się, że wszystko powinno być w porządku. ALE, gdy uruchamiasz aplikację, kod w modułach JavaFX kończy się niepowodzeniem podczas próby użycia odbicia w celu utworzenia instancji Twojej klasy aplikacji (podczas wywoływania uruchomienia) i klas kontrolera FXML (podczas ładowania FXML). Bez pewnej pomocy takie wykorzystanie refleksji może w niektórych przypadkach zawieść, generując niejasnośćIllegalAccessError
. Wynika to z funkcji zabezpieczeń systemu modułu Java, która nie pozwala kodowi z innych modułów na używanie odbicia na twoich klasach, chyba że wyraźnie na to zezwolisz (a program uruchamiający aplikacje JavaFX i FXMLLoader wymagają odzwierciedlenia w ich bieżącej implementacji, aby mogły działać prawidłowo).
W tym miejscu module-info.java
pojawiają się niektóre inne odpowiedzi na to pytanie, które zawierają odniesienie .
Zróbmy więc szybki kurs dotyczący modułów Java:
Kluczowa część jest taka:
4.9. Otwiera
Jeśli musimy zezwolić na odbicie typów prywatnych, ale nie chcemy, aby cały nasz kod był ujawniany, możemy użyć dyrektywy opens, aby ujawnić określone pakiety.
Pamiętaj jednak, że to otworzy pakiet na cały świat, więc upewnij się, że tego chcesz:
module my.module { opens com.my.package; }
Więc być może nie chcesz otwierać swojego pakietu na cały świat, możesz zrobić:
4.10. Otwiera… do
Okay, więc czasami refleksja jest świetna, ale nadal chcemy jak największego bezpieczeństwa dzięki hermetyzacji. Możemy selektywnie otwierać nasze pakiety na wstępnie zatwierdzoną listę modułów, w tym przypadku za pomocą dyrektywy opens… to:
moduł my.module {otwiera com.my.package na moduleOne, moduleTwo itd .; }
W rezultacie tworzysz klasę src / main / java / module-info.java, która wygląda następująco:
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;
}
Gdzie org.jewelsea.demo.javafx.springboot
jest nazwą pakietu zawierającego klasę aplikacji JavaFX i klasy kontrolera JavaFX (zastąp ją odpowiednią nazwą pakietu dla aplikacji). To informuje środowisko wykonawcze Java, że jest OK dla klas w javafx.graphics
ijavafx.fxml
wywołać refleksję na temat klas w org.jewelsea.demo.javafx.springboot
pakiecie . Gdy to zrobisz, a aplikacja zostanie skompilowana i ponownie uruchomiona, wszystko będzie działać dobrze, a IllegalAccessError
wygenerowane przez JavaFX odbicie nie będzie już występować.
Ale co, jeśli nie chcesz tworzyć pliku module-info.java
Jeśli zamiast używać przycisku Uruchom na górnym pasku narzędzi IDE do bezpośredniego uruchamiania klasy aplikacji, zamiast tego:
- Poszedłem do okna Mavena z boku IDE.
- Wybierz cel wtyczki javafx maven
javafx.run
.
- Kliknął prawym przyciskiem myszy i wybrał albo
Run Maven Build
albo Debug...
.
Wtedy aplikacja będzie działać bez module-info.java
pliku. Wydaje mi się, że dzieje się tak dlatego, że wtyczka maven jest wystarczająco inteligentna, aby dynamicznie włączać pewne ustawienia, które pozwalają na odzwierciedlenie aplikacji przez klasy JavaFX nawet bez module-info.java
pliku, chociaż nie wiem, jak to się dzieje.
Aby przenieść to ustawienie do przycisku Uruchom na górnym pasku narzędzi, kliknij prawym przyciskiem myszy javafx.run
cel Mavena i wybierz opcję Create Run/Debug Configuration
dla celu. Następnie możesz po prostu wybrać Uruchom z górnego paska narzędzi, aby wykonać cel Mavena.