Error de módulo al ejecutar la aplicación multimedia JavaFx
Cuando ejecuto mi JavaFX
aplicación 11 con el siguiente comando:
/usr/lib/jvm/java-11-openjdk-amd64/bin/java
-p ~/.m2/repository/org/openjfx/javafx-swing/11/javafx-swing-11.jar:
~/.m2/repository/org/openjfx/javafx-swing/11/javafx-swing-11-linux.jar:
~/.m2/repository/org/openjfx/javafx-graphics/11/javafx-graphics-11.jar:
~/.m2/repository/org/openjfx/javafx-graphics/11/javafx-graphics-11-linux.jar:
~/.m2/repository/org/openjfx/javafx-base/11/javafx-base-11.jar:
~/.m2/repository/org/openjfx/javafx-base/11/javafx-base-11-linux.jar:
~/.m2/repository/org/openjfx/javafx-controls/11/javafx-controls-11.jar:
~/.m2/repository/org/openjfx/javafx-controls/11/javafx-controls-11-linux.jar:
~/.m2/repository/org/openjfx/javafx-media/11/javafx-media-11.jar:
~/.m2/repository/org/openjfx/javafx-media/11/javafx-media-11-linux.jar
--add-modules javafx.controls,javafx.graphics
-classpath ~/development/intellij/OpenPatrician/OpenPatricianStandalone/target/classes:
~/.OpenPatrician/plugins/maps/MinimalMap-Plugin.jar:
~/development/intellij/OpenPatrician/OpenPatricianDisplay/target/classes:
~/.m2/repository/ch/sahits/sahitsUtil/1.2.4/sahitsUtil-1.2.4.jar:
~/.m2/repository/junit/junit/4.12/junit-4.12.jar:
~/.m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar:
~/.m2/repository/org/springframework/boot/spring-boot-starter-log4j2/2.1.0.RELEASE/spring-boot-starter-log4j2-2.1.0.RELEASE.jar:
~/.m2/repository/org/apache/logging/log4j/log4j-slf4j-impl/2.11.1/log4j-slf4j-impl-2.11.1.jar:
~/.m2/repository/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar:
~/.m2/repository/org/apache/logging/log4j/log4j-api/2.11.1/log4j-api-2.11.1.jar:
~/.m2/repository/org/apache/logging/log4j/log4j-core/2.11.1/log4j-core-2.11.1.jar:
~/.m2/repository/org/apache/logging/log4j/log4j-jul/2.11.1/log4j-jul-2.11.1.jar:
~/.m2/repository/org/slf4j/jul-to-slf4j/1.7.25/jul-to-slf4j-1.7.25.jar:
~/.m2/repository/commons-cli/commons-cli/1.4/commons-cli-1.4.jar:
~/development/intellij/OpenPatrician/OpenPatricianImage/target/classes:
~/development/intellij/OpenPatrician/OpenPatricianModel/target/classes:
~/development/intellij/OpenPatrician/GameEvent/target/classes:
~/.m2/repository/org/glassfish/jaxb/jaxb-runtime/2.3.1/jaxb-runtime-2.3.1.jar:
~/.m2/repository/org/glassfish/jaxb/txw2/2.3.1/txw2-2.3.1.jar:
~/.m2/repository/com/sun/istack/istack-commons-runtime/3.0.7/istack-commons-runtime-3.0.7.jar:
~/.m2/repository/org/jvnet/staxex/stax-ex/1.8/stax-ex-1.8.jar:
~/.m2/repository/com/sun/xml/fastinfoset/FastInfoset/1.2.15/FastInfoset-1.2.15.jar:
~/.m2/repository/javax/activation/javax.activation-api/1.2.0/javax.activation-api-1.2.0.jar:
~/.m2/repository/org/openjfx/javafx-swing/11/javafx-swing-11.jar:
~/.m2/repository/org/openjfx/javafx-swing/11/javafx-swing-11-linux.jar:
~/.m2/repository/org/openjfx/javafx-graphics/11/javafx-graphics-11.jar:
~/.m2/repository/org/openjfx/javafx-graphics/11/javafx-graphics-11-linux.jar:
~/.m2/repository/org/openjfx/javafx-base/11/javafx-base-11.jar:
~/.m2/repository/org/openjfx/javafx-base/11/javafx-base-11-linux.jar:
~/development/intellij/OpenPatrician/OpenPatricianSound/target/classes:
~/development/intellij/OpenPatrician/OpenPatricianUtilities/target/classes:
~/.m2/repository/org/springframework/spring-beans/5.1.2.RELEASE/spring-beans-5.1.2.RELEASE.jar:
~/.m2/repository/org/openjfx/javafx-controls/11/javafx-controls-11.jar:
~/.m2/repository/org/openjfx/javafx-controls/11/javafx-controls-11-linux.jar:
~/.m2/repository/commons-io/commons-io/2.6/commons-io-2.6.jar:
~/.m2/repository/com/thoughtworks/xstream/xstream/1.4.10/xstream-1.4.10.jar:
~/.m2/repository/xmlpull/xmlpull/1.1.3.1/xmlpull-1.1.3.1.jar:
~/.m2/repository/xpp3/xpp3_min/1.1.4c/xpp3_min-1.1.4c.jar:
~/.m2/repository/javax/xml/bind/jaxb-api/2.3.1/jaxb-api-2.3.1.jar:
~/.m2/repository/javax/annotation/javax.annotation-api/1.3.2/javax.annotation-api-1.3.2.jar:
~/.m2/repository/org/openjfx/javafx-media/11/javafx-media-11.jar:
~/.m2/repository/org/openjfx/javafx-media/11/javafx-media-11-linux.jar:
~/.m2/repository/org/springframework/spring-context/5.1.2.RELEASE/spring-context-5.1.2.RELEASE.jar:
~/.m2/repository/org/springframework/spring-aop/5.1.2.RELEASE/spring-aop-5.1.2.RELEASE.jar:
~/.m2/repository/org/springframework/spring-expression/5.1.2.RELEASE/spring-expression-5.1.2.RELEASE.jar:
~/.m2/repository/org/springframework/spring-oxm/5.1.2.RELEASE/spring-oxm-5.1.2.RELEASE.jar:
~/.m2/repository/com/google/guava/guava/24.1-jre/guava-24.1-jre.jar:
~/.m2/repository/com/google/code/findbugs/jsr305/1.3.9/jsr305-1.3.9.jar:
~/.m2/repository/org/checkerframework/checker-compat-qual/2.0.0/checker-compat-qual-2.0.0.jar:
~/.m2/repository/com/google/errorprone/error_prone_annotations/2.1.3/error_prone_annotations-2.1.3.jar:
~/.m2/repository/com/google/j2objc/j2objc-annotations/1.1/j2objc-annotations-1.1.jar:
~/.m2/repository/org/codehaus/mojo/animal-sniffer-annotations/1.14/animal-sniffer-annotations-1.14.jar:
~/development/intellij/OpenPatrician/OpenPatricianJavaFX/target/classes:
~/development/intellij/OpenPatrician/OpenPatricianGameEvent/target/classes:
~/development/intellij/OpenPatrician/OpenPatricianClientServerInterface/target/classes:
~/.m2/repository/org/springframework/boot/spring-boot-starter-aop/2.1.0.RELEASE/spring-boot-starter-aop-2.1.0.RELEASE.jar:
~/.m2/repository/org/springframework/boot/spring-boot-starter/2.1.0.RELEASE/spring-boot-starter-2.1.0.RELEASE.jar:
~/.m2/repository/org/yaml/snakeyaml/1.23/snakeyaml-1.23.jar:
~/.m2/repository/org/aspectj/aspectjweaver/1.9.2/aspectjweaver-1.9.2.jar:
~/development/intellij/OpenPatrician/OpenPatricianServer/target/classes:
~/development/intellij/OpenPatrician/OpenPatricianEngine/target/classes:
~/.m2/repository/com/carrotsearch/hppc/0.7.2/hppc-0.7.2.jar:
~/.m2/repository/org/springframework/spring-core/5.1.2.RELEASE/spring-core-5.1.2.RELEASE.jar:
~/.m2/repository/org/springframework/spring-jcl/5.1.2.RELEASE/spring-jcl-5.1.2.RELEASE.jar:
~/.m2/repository/org/reflections/reflections/0.9.11/reflections-0.9.11.jar:
~/.m2/repository/org/javassist/javassist/3.21.0-GA/javassist-3.21.0-GA.jar:
~/development/intellij/OpenPatrician/OpenPatricianData/target/classes:
~/.m2/repository/org/projectlombok/lombok/1.18.2/lombok-1.18.2.jar:
~/.m2/repository/org/springframework/boot/spring-boot-devtools/2.1.0.RELEASE/spring-boot-devtools-2.1.0.RELEASE.jar:
~/.m2/repository/org/springframework/boot/spring-boot/2.1.0.RELEASE/spring-boot-2.1.0.RELEASE.jar:
~/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/2.1.0.RELEASE/spring-boot-autoconfigure-2.1.0.RELEASE.jar
ch.sahits.game.openpatrician.standalone.OpenPatricianApplication
Me encuentro con este error:
Exception in thread "JavaFX Application Thread" java.lang.IllegalAccessError: class com.sun.media.jfxmediaimpl.NativeMediaManager (in unnamed module @0x4d7be377) cannot access class com.sun.glass.utils.NativeLibLoader (in module javafx.graphics) because module javafx.graphics does not export com.sun.glass.utils to unnamed module @0x4d7be377
at com.sun.media.jfxmediaimpl.NativeMediaManager.lambda$new$0(NativeMediaManager.java:136)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at com.sun.media.jfxmediaimpl.NativeMediaManager.<init>(NativeMediaManager.java:107)
at com.sun.media.jfxmediaimpl.NativeMediaManager$NativeMediaManagerInitializer.<clinit>(NativeMediaManager.java:78)
at com.sun.media.jfxmediaimpl.NativeMediaManager.getDefaultInstance(NativeMediaManager.java:90)
at com.sun.media.jfxmedia.MediaManager.canPlayProtocol(MediaManager.java:78)
at com.sun.media.jfxmedia.locator.Locator.<init>(Locator.java:239)
at com.sun.media.jfxmediaimpl.NativeMediaAudioClip.<init>(NativeMediaAudioClip.java:53)
at com.sun.media.jfxmediaimpl.NativeMediaAudioClip.load(NativeMediaAudioClip.java:63)
at com.sun.media.jfxmediaimpl.AudioClipProvider.load(AudioClipProvider.java:66)
at com.sun.media.jfxmedia.AudioClip.load(AudioClip.java:135)
at javafx.scene.media.AudioClip.<init>(AudioClip.java:83)
at ch.sahits.game.openpatrician.sound.impl.LoopTrack.lambda$new$0(LoopTrack.java:26)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
at java.base/java.security.AccessController.doPrivileged(Native Method)
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)
at javafx.graphics/com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
at javafx.graphics/com.sun.glass.ui.gtk.GtkApplication.lambda$runLoop$11(GtkApplication.java:277)
at java.base/java.lang.Thread.run(Thread.java:834)
Según tengo entendido, hay algún problema con la configuración de mi módulo, pero no tengo claro qué debo cambiar:
- ¿Agregar módulos adicionales a
--add-modules
y cuáles? - Agregar
--add-opens
al comando con qué módulos - ¿Algo completamente diferente?
TL;DR: Debe asegurarse de javafx.media
que se resuelva como un módulo desde la ruta del módulo. Puedes hacer esto mediante:
Incluyéndolo en los argumentos de VM:
--add-modules javafx.controls,javafx.media
O hacer que su propio código sea modular, agregar una
requires javafx.media;
directiva apropiada al descriptor de su módulo y usarla--module
para iniciar su aplicación.O usando un JDK que incluya JavaFX.
Si no está seguro de cómo o dónde configurar los argumentos de VM en su IDE y/o herramienta de compilación, consulte Introducción a JavaFX .
El problema
El error está relacionado con Java Platform Module System , agregado en Java 9. Si no sabe qué son los módulos y cómo funcionan, consulte este blog: Comprensión de los módulos de Java 9 . Aquí hay un pequeño extracto:
La modularidad agrega un mayor nivel de agregación por encima de los paquetes. El elemento clave del nuevo lenguaje es el módulo: un grupo reutilizable de paquetes relacionados con un nombre exclusivo, así como recursos (como imágenes y archivos XML) y un descriptor de módulo que especifica
- el nombre del módulo
- las dependencias del módulo (es decir, otros módulos de los que depende este módulo)
- los paquetes que explícitamente pone a disposición de otros módulos (todos los demás paquetes en el módulo implícitamente no están disponibles para otros módulos)
- los servicios que ofrece
- los servicios que consume
- a qué otros módulos permite la reflexión
Con la introducción de módulos, JavaFX también se modularizó. Ahora está compuesto por siete módulos, como puede verse en su Javadoc . Estos módulos comparten algunos de sus componentes internos entre ellos, pero no con los desarrolladores de aplicaciones. Esto se logra a través de directivas calificadas de exportación/apertura.
Tu error
Este es tu error:
java.lang.IllegalAccessError: class com.sun.media.jfxmediaimpl.NativeMediaManager (in unnamed module @0x4d7be377) cannot access class com.sun.glass.utils.NativeLibLoader (in module javafx.graphics) because module javafx.graphics does not export com.sun.glass.utils to unnamed module @0x4d7be377
Le indica que una clase en el módulo sin nombre está intentando acceder a una clase en un módulo con nombre diferente: javafx.graphics
. Sin embargo, el último módulo no exporta el paquete necesario al menos al módulo sin nombre. Al observar el mensaje de error y los nombres de clase dados, podemos deducir que la clase en el módulo sin nombre es parte de la implementación de medios de JavaFX. Esto sugiere que la clase debería estar en el javafx.media
módulo. Entonces, ¿por qué el error menciona el módulo sin nombre?
El módulo sin nombre es el módulo al que pertenecen todas las clases en la ruta de clases. Lo que esto significa es que el javafx.media
módulo se colocó en el class-path y perdió su identidad. Una consecuencia de esto es que todas las directivas de exportaciones/aperturas calificadas declaradas por el javafx.graphics
módulo que le otorgan javafx.media
el acceso necesario ya no se aplican; de ahí el IllegalAccessError
.
Pero... Usaste la ruta del módulo
Desde la línea de comando que proporcionó en su pregunta, podemos ver que el javafx-media-11.jar
archivo se colocó en la ruta del módulo ( -p
). Entonces, ¿cuál es el problema? El problema se debe a que el archivo JAR multimedia se coloca tanto en la ruta del módulo como en la ruta de clase, y al mismo tiempo no se garantiza que el javafx.media
módulo se resuelva como un módulo.
El algoritmo para la resolución del módulo se describe en la java.lang.module
documentación del paquete. Básicamente, comienza con un conjunto de módulos raíz y luego enumera recursivamente las directivas requeridas. Los módulos raíz están determinados por los argumentos --add-modules
y --module
. Su código no es modular, lo que significa que no usa --module
y tiene:
--add-modules javafx.controls,javafx.graphics
En otras palabras, ninguno de los módulos raíz requiere directa o indirectamente el javafx.media
módulo, por lo que nunca se resuelve. Dado que las clases también están en la ruta de clases, todavía se encuentran, pero ahora en el módulo sin nombre. Si no hubiera colocado también las dependencias de JavaFX en la ruta de clase, entonces obtendría un archivo ClassNotFoundException
.
La solución
La solución es simple: asegúrese de que el javafx.media
módulo esté resuelto. Hay al menos tres maneras de lograr esto:
(1) Incluir el módulo en el --add-modules
argumento
--add-modules javafx.controls,javafx.media
Tenga en cuenta que no necesita especificar el javafx.graphics
módulo, ya que los otros módulos lo incorporarán implícitamente; ambos javafx.controls
y javafx.media
requieren javafx.graphics
. javafx.base
El mismo razonamiento general se aplica en este caso también al módulo.
Las guías de Introducción a JavaFX muestran cómo configurar las opciones de VM para JavaFX en cada uno de los principales IDE (es decir, IntelliJ, Eclipse y NetBeans) y herramientas de compilación (es decir, Maven y Gradle).
(2) Haga su propio código modular
module app {
requires javafx.controls;
requires javafx.media;
// replace with your Application class' package
exports com.example.app to javafx.graphics;
}
Luego, asegúrese de iniciar su aplicación --module
(espero que las versiones modernas de IDE y herramientas de compilación lo hagan por usted si su código tiene un module-info
descriptor).
Observe las exportaciones calificadas a javafx.graphics
. Esto es necesario para que JavaFX cree una instancia reflexiva de su clase de aplicación. Existen requisitos similares (calificados opens
) para los controladores FXML y otras API que requieren acceso reflexivo privado.
(3) Utilice un JDK que incluya JavaFX
Dado que JavaFX forma parte de la imagen en tiempo de ejecución, siempre se resolverá como módulos con nombre. Hay dos distribuciones de OpenJDK que incluyen OpenJFX que yo sepa:
BellSoft Liberica (asegúrese de descargar "Full JDK")
Azul Zulu (asegúrate de descargar "JDK FX")
Tenga en cuenta que también es posible crear su propio JDK mediantejlink
.
"Solución" de rebotes
Advertencia: este enfoque no es compatible .
Hay otra opción: colocar todo en la ruta de clase, incluidos los módulos JavaFX, e ignorar los módulos JPMS por completo. Si hace esto, su clase principal no debe ser una subclase de Application
. Tendría que crear una clase de iniciador separada que simplemente inicie JavaFX.
Si usa Maven, puede ver cómo confiar en el módulo multimedia JavaFX aquí como una dependencia aquí:
- Importación del reproductor multimedia JavaFX (Maven)
Si está utilizando VSCode
, aquí tiene una solución simple a su problema:
En el proyecto java existe una carpeta llamada .vscode
, dentro de esta existe un archivo .json llamado launch.json
.
directorio: Imagen
lanzamiento.json:
{
"version": "0.2.0",
"configurations": [
{
"type": "java",
"name": "Launch Main",
"request": "launch",
"vmArgs": "--module-path /Users/ASUS/javafx-sdk-16/lib --add-modules javafx.controls,javafx.fxml",
"mainClass": "main.java.Main",
"projectName": "MorseJavaFx_41229da3"
},
{
"type": "java",
"name": "Launch Current File",
"request": "launch",
"mainClass": "${file}"
}
]
}
Entonces, en la línea " vmArgs
", debes agregar javafx.media
al final y dentro de las comillas, así:
"vmArgs": "--module-path /Users/ASUS/javafx-sdk-16/lib --add-modules javafx.controls,javafx.fxml, javafx.media"
Disfruta.😄