TL;DR: You need to make sure javafx.media
is resolved as a module from the module-path. You can do this by either:
- Including it in the VM arguments:
--add-modules javafx.controls,javafx.media
- Or making your own code modular, adding an appropriate
requires javafx.media;
directive to your module descriptor, and using --module
to launch your application.
If you're not sure how or where to set the VM arguments in your IDE and/or build tool, check out Getting Started with JavaFX.
The Problem
The error is related to the Java Platform Module System, added in Java 9. If you're not aware of what modules are and how they work, check out this blog: Understanding Java 9 Modules. Here's a small excerpt:
Modularity adds a higher level of aggregation above packages. The key new language element is the module—a uniquely named, reusable group of related packages, as well as resources (such as images and XML files) and a module descriptor specifying
- the module’s name
- the module’s dependencies (that is, other modules this module depends on)
- the packages it explicitly makes available to other modules (all other packages in the module are implicitly unavailable to other modules)
- the services it offers
- the services it consumes
- to what other modules it allows reflection
With the introduction of modules, JavaFX was also modularized. It is now made up of seven modules, as can be seen by its Javadoc. These modules share some of their internals between themselves, but not with application developers. This is accomplished through qualified exports/opens directives.
Your Error
This is your 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
It's telling you a class in the unnamed module is attempting to access a class in a different, named module: javafx.graphics
. However, the latter module does not export the needed package to at least the unnamed module. Looking at the error message and the given class names, we can deduce that the class in the unnamed module is part of JavaFX's media implementation. This suggests the class should be in the javafx.media
module. Then why does the error mention the unnamed module?
The unnamed module is the module all classes on the class-path belong to. What this means is that the javafx.media
module was put on the class-path and lost its identity. A consequence of this is that all the qualified exports/opens directives declared by the javafx.graphics
module which grant the javafx.media
module the necessary access no longer apply—hence the IllegalAccessError
.
But... You Used the Module-Path
From the command line you provided in your question we can see the javafx-media-11.jar
file was placed on the module-path (-p
). So what is the problem? The problem is caused by placing the media JAR file on both the module-path and the class-path, while simultaneously failing to ensure the javafx.media
module is resolved as a module.
The algorithm for module resolution is described by the java.lang.module
package documentation. Basically, it starts with a set of root modules and then recursively enumerates the requires directives. The root modules are determined by the --add-modules
and --module
arguments. Your code isn't modular, meaning you don't use --module
, and you have:
--add-modules javafx.controls,javafx.graphics
In other words, none of the root modules directly or indirectly require the javafx.media
module, thus it is never resolved. Since the classes are also on the class-path they're still found, but now in the unnamed module. If you had not placed the JavaFX dependencies on the class-path as well then you'd be getting a ClassNotFoundException
.
The Solution
The solution is simple: Make sure the javafx.media
module is resolved. There are at least two ways to accomplish this:
Include the module in your --add-modules
argument.
--add-modules javafx.controls,javafx.media
Note you don't need to specify the javafx.graphics
module as it'll be pulled in implicitly by the other modules; both javafx.controls
and javafx.media
require javafx.graphics
. The same general reasoning also applies to the javafx.base
module in this case.
The Getting Started with JavaFX guides show how to configure the VM options for JavaFX in each of the major IDEs (i.e. IntelliJ, Eclipse, and NetBeans) and build tools (i.e. Maven and Gradle).
Make your own code modular and add the necessary requires directives.
module app {
requires javafx.controls;
requires javafx.media;
// replace with your Application class' package
exports com.example.app to javafx.graphics;
}
Then make sure to launch your application with --module
.
Notice the qualified exports to javafx.graphics
. This is required in order for JavaFX to reflectively instantiate your application class. There are similar requirements (qualified opens
) for FXML controllers and other APIs which require private reflective access.
There is another option: Place everything on the class-path, including the JavaFX modules, and ignore JPMS modules completely. If you do this your main-class must not be a subclass of Application
. You'd have to create a separate launcher class that simply launches JavaFX. Warning: This approach is not supported.