Краткое резюме, вы можете сделать либо:
Включите модули JavaFX через --module-path
и--add-modules
как в ответе Хосе.
ИЛИ ЖЕ
После добавления в проект библиотек JavaFX (вручную или с помощью импорта maven / gradle) добавьте module-info.java
файл, аналогичный тому, который указан в этом ответе. (Обратите внимание, что это решение делает ваше приложение модульным, поэтому, если вы используете другие библиотеки, вам также нужно будет добавить операторы, чтобы требовать их модули внутри module-info.java
файла).
Этот ответ является дополнением к ответу Хосе.
Ситуация такая:
- Вы используете последнюю версию Java, например 13.
- У вас есть приложение JavaFX как проект Maven.
- В вашем проекте Maven у вас настроен плагин JavaFX и установлены зависимости JavaFX в соответствии с ответом Хосе.
- Вы переходите к исходному коду вашего основного класса, расширяющего Application, щелкаете его правой кнопкой мыши и пытаетесь запустить.
IllegalAccessError
При попытке запустить приложение вы получаете сообщение о «неназванном модуле».
Выдержка для трассировки стека, генерирующей сообщение IllegalAccessError
при попытке запустить приложение JavaFX из 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
Хорошо, теперь вы как бы застряли и не понимаете, что происходит.
На самом деле произошло следующее:
- Maven успешно загрузил зависимости JavaFX для вашего приложения, поэтому вам не нужно отдельно загружать зависимости или устанавливать JavaFX SDK, дистрибутив модуля или что-то подобное.
- Idea успешно импортировала модули в качестве зависимостей в ваш проект, поэтому все компилируется нормально, весь код завершается, и все работает нормально.
Так что вроде все должно быть ОК. НО, когда вы запускаете свое приложение, код в модулях JavaFX дает сбой при попытке использовать отражение для создания экземпляров вашего класса приложения (когда вы вызываете запуск) и ваших классов контроллера FXML (когда вы загружаете FXML). Без какой-либо помощи такое использование отражения в некоторых случаях может дать сбой, создавая неясныеIllegalAccessError
. Это связано с функцией безопасности системы модуля Java, которая не позволяет коду из других модулей использовать отражение в ваших классах, если вы явно не разрешите это (а средство запуска приложений JavaFX и FXMLLoader требуют отражения в своей текущей реализации, чтобы они функционировали правильно).
Здесь приведены некоторые другие ответы на этот вопрос, относящиеся к module-info.java
появляются .
Итак, давайте пройдем ускоренный курс по модулям Java:
Ключевая часть такова:
4.9. Открывается
Если нам нужно разрешить отражение частных типов, но мы не хотим, чтобы весь наш код был открыт, мы можем использовать директиву opens для предоставления определенных пакетов.
Но помните, что это откроет пакет для всего мира, поэтому убедитесь, что это то, что вы хотите:
module my.module { opens com.my.package; }
Итак, возможно, вы не хотите открывать свой пакет для всего мира, тогда вы можете сделать:
4.10. Открывается…
Хорошо, иногда отражение - это здорово, но мы все же хотим максимальной безопасности, которую мы можем получить от инкапсуляции. Мы можем выборочно открывать наши пакеты для предварительно утвержденного списка модулей, в данном случае с помощью директивы opens… to:
module my.module {открывает com.my.package в moduleOne, moduleTwo и т. д .; }
Итак, вы создаете класс src / main / java / module-info.java, который выглядит так:
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;
}
Где, org.jewelsea.demo.javafx.springboot
- это имя пакета, который содержит класс приложения JavaFX и классы контроллера JavaFX (замените его на соответствующее имя пакета для вашего приложения). Это сообщает среде выполнения Java, что для классов в javafx.graphics
и javafx.fxml
можно вызывать отражение классов в вашем org.jewelsea.demo.javafx.springboot
пакете. Как только это будет сделано, и приложение скомпилировано и повторно запущено, все будет работать нормально, и IllegalAccessError
отражение, сгенерированное JavaFX, больше не будет происходить.
Но что, если вы не хотите создавать файл module-info.java
Если вместо использования кнопки «Выполнить» на верхней панели инструментов среды IDE для непосредственного запуска класса приложения вы:
- Зашел в окно Maven в стороне от IDE.
- Выберите цель плагина javafx maven
javafx.run
.
- Щелкните правой кнопкой мыши и выберите либо
Run Maven Build
или Debug...
.
Тогда приложение будет работать без module-info.java
файла. Я предполагаю, что это связано с тем, что плагин maven достаточно умен, чтобы динамически включать некоторые настройки, которые позволяют отражать приложение в классах JavaFX даже безmodule-info.java
файла, хотя я не знаю, как это достигается.
Чтобы перенести этот параметр на кнопку «Выполнить» на верхней панели инструментов, щелкните правой кнопкой мыши javafx.run
цель Maven и выберите параметр Create Run/Debug Configuration
для цели. Затем вы можете просто выбрать «Выполнить» на верхней панели инструментов, чтобы выполнить цель Maven.