Module error when running JavaFx media application

TL;DR: You need to make sure javafx.media is resolved as a module from the module-path. You can do this by either:

  1. Including it in the VM arguments: --add-modules javafx.controls,javafx.media
  2. 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:

  1. 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).

  2. 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.


If you use Maven, you can see how to rely on the JavaFX media module here as a dependency here:

Leave a Comment