Tengo una aplicación JavaFX muy básico que funciona a la perfección si la clase de aplicación es no la clase principal:
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.stage.Stage;
public class Main {
public static void main(String[] args) {
Application.launch(App.class, args);
}
}
public class App extends Application {
@Override
public void start(Stage primaryStage) {
FXMLLoader loader = new FXMLLoader(); // works
}
}
Sin embargo, cuando fusionar las dos juntas (que es la forma recomendada en la mayoría de los tutoriales, incluyendo la documentación oficial de OpenJFX ), el sistema de módulos lanza una IllegalAccessError
(al menos en OpenJDK 11.0.2):
public class MainApp extends Application {
@Override
public void start(Stage primaryStage) {
FXMLLoader loader = new FXMLLoader(); // throws IllegalAccessError
}
public static void main(String[] args) {
launch(MainApp.class, args);
}
}
La excepción es:
java.lang.IllegalAccessError: clase
com.sun.javafx.fxml.FXMLLoaderHelper
(en el módulo sin nombre@0x642c1a1b
) no puede clase de accesocom.sun.javafx.util.Utils
(en el módulojavafx.graphics
), porque el módulojavafx.graphics
no exportarcom.sun.javafx.util
al módulo sin nombre@0x642c1a1b
Lo extraño es, que no utilizan activamente el sistema de módulos. No añadí una module-info.java
a mi proyecto. Así que supuse que todo debe conseguir exportado a cualquier módulo sin nombre? Pero eso no es ni siquiera el punto.
La cuestión principal es: ¿Por qué se comportan del mismo código diferente si distribuye a través de dos clases? En ambos casos, FXMLLoader
los usos com.sun.javafx.fxml.FXMLLoaderHelper
, los cuales a su vez en usos com.sun.javafx.util.Utils
. Así que, o que debería obtener la excepción en ambos casos o en ninguno. ¿Cuál es la diferencia?
Hay algunas respuestas que habían puesto que podría aplicarse en parte a sus preguntas, pero podría ser conveniente recogerlos aquí y presentarlos de una respuesta completa.
clase de aplicación
En la respuesta a Maven sombra componentes de ejecución de JavaFX se echa en falta me explicó la razón por la cual, cuando se utiliza la Application
clase como su clase principal, se espera que utilice el sistema de módulos.
En resumen:
Como se puede leer aquí :
Este error proviene de
sun.launcher.LauncherHelper
en el módulo java.base ( enlace ).Si la aplicación principal se extiende
Application
y tiene unmain
método, laLauncherHelper
comprobaremos para eljavafx.graphics
módulo para estar presente como un módulo denominado:
Optional<Module> om = ModuleLayer.boot().findModule(JAVAFX_GRAPHICS_MODULE_NAME);
if (!om.isPresent()) {
abort(null, "java.launcher.cls.error5");
}
Si ese módulo no está presente, el lanzamiento se aborta.
Cada frasco de JavaFX 11 tiene un module-info.class
archivo, por lo que, por definición, se espera que éstos se añade a la ruta del módulo.
Pero si no se ejecutan a través de Application
la clase, que el registro no se realiza.
Clase principal
Esta otra respuesta a un comportamiento diferente entre Maven y Eclipse para lanzar una aplicación JavaFX 11 explica por qué funciona sin el sistema modular cuando se utiliza una Launcher
clase (una clase principal que no se extiende Aplicación) con el Maven exec:java
plugin.
En resumen:
- El uso de un lanzador se requiere para superar el mencionado
sun.launcher.LauncherHelper
tema. - Al igual que los plugin se ejecuta maven en la ruta de clase, cargando todas las dependencias en una rosca aislado, lo mismo ocurre con IntelliJ en este caso.
Si marca la línea de comandos al ejecutar Main.main()
:
/path/to/jdk-11.0.2.jdk/Contents/Home/bin/java \
"-javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=60556:/Applications/IntelliJ IDEA.app/Contents/bin" \
-Dfile.encoding=UTF-8 \
-classpath /path/to/so-question-54756176-master/target/classes:/path/to/.m2/repository/org/openjfx/javafx-base/11.0.2/javafx-base-11.0.2.jar:.../path/to/.m2/repository/org/openjfx/javafx-fxml/11.0.2/javafx-fxml-11.0.2-mac.jar \
Main
Todos los frascos de JavaFX JavaFX SDK se añaden a la ruta de clase, y está ejecutando el clásico java -cp ... Main
.
javafx.fxml falta
Estos otra respuesta a IntelliJ IDEA - Error: componentes de ejecución de JavaFX se echa en falta, y se requieren para ejecutar esta aplicación se explica el error que se obtiene cuando se ejecuta en el sistema de módulos, pero no se agrega javafx.fxml
a la --add-modules
opción.
Caused by: java.lang.IllegalAccessError: class com.sun.javafx.fxml.FXMLLoaderHelper (in unnamed module @0x5fce9dc5) 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 @0x5fce9dc5
at com.sun.javafx.fxml.FXMLLoaderHelper.<clinit>(FXMLLoaderHelper.java:38)
at javafx.fxml.FXMLLoader.<clinit>(FXMLLoader.java:2056)
Su error dice que está utilizando FXML pero no se puede resolver en el módulo de la ruta, por lo que está intentando acceder a través de la reflexión y que no logra ya que usted no abrió que javafx.graphics
a su módulo sin nombre.
Así que ahora usted se preguntará: Yo no puse el javafx.graphics
en el primer lugar!
Bueno, no lo hizo, pero IntelliJ lo hizo por ti!
Compruebe la línea de comandos al ejecutar MainApp.main()
:
/path/to/jdk-11.0.2.jdk/Contents/Home/bin/java \
--add-modules javafx.base,javafx.graphics \
--add-reads javafx.base=ALL-UNNAMED \
--add-reads javafx.graphics=ALL-UNNAMED \
"-javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=60430:/Applications/IntelliJ IDEA.app/Contents/bin" \
-Dfile.encoding=UTF-8 \
-classpath /path/to/so-question-54756176-master/target/classes:/path/to/.m2/repository/org/openjfx/javafx-base/11.0.2/javafx-base-11.0.2.jar:.../.m2/repository/org/openjfx/javafx-graphics/11.0.2/javafx-graphics-11.0.2-mac.jar \
MainApp
Se puede ver que IntelliJ agrega de forma predeterminada javafx.base
y javafx.graphics
. Por lo que sólo la javafx.fxml
falta (y entonces usted debe, por supuesto, añadir el módulo de ruta).
La solución recomendada, como usted ha señalado, se encuentra en los documentos :
Ya sea en la línea de comandos, utilizando --module-path
para incluir la ruta de la carpeta de la liberación de JavaFX SDK, y --add-modules
para incluir javafx.fxml
en este caso (en el que no tiene controles).
O usando el plugin de Maven. En algún momento tendrá que salir de su IDE, por lo que tendrá que utilizar un plugin para ejecutar la aplicación.
ejecución Maven
Una nota final sobre el Maven exec
plugin, en caso de que se utilice:
Lo que es más, la solución Maven recomendada, hasta que el complemento exec:java
se fija para el sistema modular (y la noticia buena es que esto está siendo hecho en estos momentos ), va a utilizar exec:exec
en su lugar, como se explica en este tema , por lo que puede especificar tanto vm argumentos.