javafxjava-modulejlinkjdeps

How to properly get the jdk modules for a fat JavaFX jar using jdeps


Just build a javafx applicationm, made a fat jar and now I want to generate a custom runtime with the jdk modules that the fat jar needs.

I've created the fat jar which works perfectly from console: ( there is however this warning WARNING: Unsupported JavaFX configuration: classes were loaded from 'unnamed module @4efb10bd' ).

What I tried next is to list the jdk modules needed by this jar:

jdeps --print-module-deps mouseMove-1.0.jar


    javafx.base
   ch.qos.logback.classic.ViewStatusMessagesServlet   -> javax.servlet.http.HttpServletRequest              not found
   ch.qos.logback.classic.ViewStatusMessagesServlet   -> javax.servlet.http.HttpServletResponse             not found
   ch.qos.logback.classic.helpers.MDCInsertingServletFilter -> javax.servlet.Filter                               not found
   ch.qos.logback.classic.helpers.MDCInsertingServletFilter -> javax.servlet.FilterChain                          not found
   ch.qos.logback.classic.helpers.MDCInsertingServletFilter -> javax.servlet.FilterConfig                         not found
   ch.qos.logback.classic.helpers.MDCInsertingServletFilter -> javax.servlet.ServletException                     not found
   ch.qos.logback.classic.helpers.MDCInsertingServletFilter -> javax.servlet.ServletRequest                       not found
   ch.qos.logback.classic.helpers.MDCInsertingServletFilter -> javax.servlet.ServletResponse                      not found
   ch.qos.logback.classic.helpers.MDCInsertingServletFilter -> javax.servlet.http.HttpServletRequest              not found
   ch.qos.logback.classic.jul.JULHelper               -> java.util.logging.Level                            not found
   ch.qos.logback.classic.jul.JULHelper               -> java.util.logging.Logger                           not found
   ch.qos.logback.classic.jul.LevelChangePropagator   -> java.util.logging.Level                            not found
   ch.qos.logback.classic.jul.LevelChangePropagator   -> java.util.logging.LogManager                       not found
   ch.qos.logback.classic.jul.LevelChangePropagator   -> java.util.logging.Logger                           not found
   ch.qos.logback.classic.selector.ContextJNDISelector -> javax.naming.Context                               not found
   ch.qos.logback.classic.selector.ContextJNDISelector -> javax.naming.NamingException                       not found
   ch.qos.logback.classic.selector.servlet.ContextDetachingSCL -> javax.naming.Context                               not found
   ch.qos.logback.classic.selector.servlet.ContextDetachingSCL -> javax.naming.NamingException                       not found
   ch.qos.logback.classic.selector.servlet.ContextDetachingSCL -> javax.servlet.ServletContextEvent                  not found
   ch.qos.logback.classic.selector.servlet.ContextDetachingSCL -> javax.servlet.ServletContextListener               not found
   ch.qos.logback.classic.selector.servlet.LoggerContextFilter -> javax.servlet.Filter                               not found
   ch.qos.logback.classic.selector.servlet.LoggerContextFilter -> javax.servlet.FilterChain                          not found
   ch.qos.logback.classic.selector.servlet.LoggerContextFilter -> javax.servlet.FilterConfig                         not found
   ch.qos.logback.classic.selector.servlet.LoggerContextFilter -> javax.servlet.ServletException                     not found
   ch.qos.logback.classic.selector.servlet.LoggerContextFilter -> javax.servlet.ServletRequest                       not found
   ch.qos.logback.classic.selector.servlet.LoggerContextFilter -> javax.servlet.ServletResponse                      not found
   ch.qos.logback.classic.servlet.LogbackServletContainerInitializer -> javax.servlet.ServletContainerInitializer          not found
   ch.qos.logback.classic.servlet.LogbackServletContainerInitializer -> javax.servlet.ServletContext                       not found
   ch.qos.logback.classic.servlet.LogbackServletContainerInitializer -> javax.servlet.ServletException                     not found
   ch.qos.logback.classic.servlet.LogbackServletContextListener -> javax.servlet.ServletContextEvent                  not found
   ch.qos.logback.classic.servlet.LogbackServletContextListener -> javax.servlet.ServletContextListener               not found
   ch.qos.logback.core.boolex.JaninoEventEvaluatorBase -> org.codehaus.janino.ScriptEvaluator                not found
   ch.qos.logback.core.joran.conditional.PropertyEvalScriptBuilder -> org.codehaus.commons.compiler.CompileException     not found
   ch.qos.logback.core.joran.conditional.PropertyEvalScriptBuilder -> org.codehaus.janino.ClassBodyEvaluator             not found
   ch.qos.logback.core.model.processor.InsertFromJNDIModelHandler -> javax.naming.Context                               not found
   ch.qos.logback.core.model.processor.InsertFromJNDIModelHandler -> javax.naming.NamingException                       not found
   ch.qos.logback.core.net.LoginAuthenticator         -> javax.mail.Authenticator                           not found
   ch.qos.logback.core.net.LoginAuthenticator         -> javax.mail.PasswordAuthentication                  not found
   ch.qos.logback.core.net.SMTPAppenderBase           -> javax.mail.Address                                 not found
   ch.qos.logback.core.net.SMTPAppenderBase           -> javax.mail.Authenticator                           not found
   ch.qos.logback.core.net.SMTPAppenderBase           -> javax.mail.BodyPart                                not found
   ch.qos.logback.core.net.SMTPAppenderBase           -> javax.mail.Message                                 not found
   ch.qos.logback.core.net.SMTPAppenderBase           -> javax.mail.Message$RecipientType                   not found
   ch.qos.logback.core.net.SMTPAppenderBase           -> javax.mail.Multipart                               not found
   ch.qos.logback.core.net.SMTPAppenderBase           -> javax.mail.Session                                 not found
   ch.qos.logback.core.net.SMTPAppenderBase           -> javax.mail.Transport                               not found
   ch.qos.logback.core.net.SMTPAppenderBase           -> javax.mail.internet.AddressException               not found
   ch.qos.logback.core.net.SMTPAppenderBase           -> javax.mail.internet.InternetAddress                not found
   ch.qos.logback.core.net.SMTPAppenderBase           -> javax.mail.internet.MimeBodyPart                   not found
   ch.qos.logback.core.net.SMTPAppenderBase           -> javax.mail.internet.MimeMessage                    not found
   ch.qos.logback.core.net.SMTPAppenderBase           -> javax.mail.internet.MimeMultipart                  not found
   ch.qos.logback.core.net.SMTPAppenderBase           -> javax.naming.Context                               not found
   ch.qos.logback.core.status.ViewStatusMessagesServletBase -> javax.servlet.ServletException                     not found
   ch.qos.logback.core.status.ViewStatusMessagesServletBase -> javax.servlet.http.HttpServlet                     not found
   ch.qos.logback.core.status.ViewStatusMessagesServletBase -> javax.servlet.http.HttpServletRequest              not found
   ch.qos.logback.core.status.ViewStatusMessagesServletBase -> javax.servlet.http.HttpServletResponse             not found
   ch.qos.logback.core.testUtil.MockInitialContext    -> javax.naming.InitialContext                        not found
   ch.qos.logback.core.testUtil.MockInitialContext    -> javax.naming.NamingException                       not found
   ch.qos.logback.core.testUtil.MockInitialContextFactory -> javax.naming.Context                               not found
   ch.qos.logback.core.testUtil.MockInitialContextFactory -> javax.naming.NamingException                       not found
   ch.qos.logback.core.testUtil.MockInitialContextFactory -> javax.naming.spi.InitialContextFactory             not found
   ch.qos.logback.core.util.JNDIUtil                  -> javax.naming.Context                               not found
   ch.qos.logback.core.util.JNDIUtil                  -> javax.naming.InitialContext                        not found
   ch.qos.logback.core.util.JNDIUtil                  -> javax.naming.NamingException                       not found
   com.sun.javafx.logging.jfr.JFRInputEvent           -> jdk.jfr.Category                                   not found
   com.sun.javafx.logging.jfr.JFRInputEvent           -> jdk.jfr.Description                                not found
   com.sun.javafx.logging.jfr.JFRInputEvent           -> jdk.jfr.Enabled                                    not found
   com.sun.javafx.logging.jfr.JFRInputEvent           -> jdk.jfr.Event                                      not found
   com.sun.javafx.logging.jfr.JFRInputEvent           -> jdk.jfr.Label                                      not found
   com.sun.javafx.logging.jfr.JFRInputEvent           -> jdk.jfr.Name                                       not found
   com.sun.javafx.logging.jfr.JFRInputEvent           -> jdk.jfr.StackTrace                                 not found
   com.sun.javafx.logging.jfr.JFRPulseLogger          -> jdk.jfr.FlightRecorder                             not found
   com.sun.javafx.logging.jfr.JFRPulsePhaseEvent      -> jdk.jfr.Category                                   not found
   com.sun.javafx.logging.jfr.JFRPulsePhaseEvent      -> jdk.jfr.Description                                not found
   com.sun.javafx.logging.jfr.JFRPulsePhaseEvent      -> jdk.jfr.Enabled                                    not found
   com.sun.javafx.logging.jfr.JFRPulsePhaseEvent      -> jdk.jfr.Event                                      not found
   com.sun.javafx.logging.jfr.JFRPulsePhaseEvent      -> jdk.jfr.Label                                      not found
   com.sun.javafx.logging.jfr.JFRPulsePhaseEvent      -> jdk.jfr.Name                                       not found
   com.sun.javafx.logging.jfr.JFRPulsePhaseEvent      -> jdk.jfr.StackTrace                                 not found
   com.sun.javafx.logging.jfr.PulseId                 -> jdk.jfr.Description                                not found
   com.sun.javafx.logging.jfr.PulseId                 -> jdk.jfr.Name                                       not found
   com.sun.javafx.logging.jfr.PulseId                 -> jdk.jfr.Relational                                 not found
   com.sun.jna.Native                                 -> java.util.logging.Level                            not found
   com.sun.jna.Native                                 -> java.util.logging.Logger                           not found
   com.sun.jna.Native$1                               -> java.util.logging.Level                            not found
   com.sun.jna.Native$1                               -> java.util.logging.Logger                           not found
   com.sun.jna.NativeLibrary                          -> java.util.logging.Level                            not found
   com.sun.jna.NativeLibrary                          -> java.util.logging.Logger                           not found
   com.sun.jna.Platform                               -> java.util.logging.Level                            not found
   com.sun.jna.Platform                               -> java.util.logging.Logger                           not found
   com.sun.jna.Structure                              -> java.util.logging.Level                            not found
   com.sun.jna.Structure                              -> java.util.logging.Logger                           not found
   com.sun.jna.internal.Cleaner$1                     -> java.util.logging.Level                            not found
   com.sun.jna.internal.Cleaner$1                     -> java.util.logging.Logger                           not found
   com.sun.jna.internal.ReflectionUtils               -> java.util.logging.Level                            not found
   com.sun.jna.internal.ReflectionUtils               -> java.util.logging.Logger                           not found
   com.sun.jna.platform.WindowUtils                   -> java.util.logging.Logger                           not found
   com.sun.jna.platform.WindowUtils$MacWindowUtils    -> java.util.logging.Level                            not found
   com.sun.jna.platform.WindowUtils$MacWindowUtils    -> java.util.logging.Logger                           not found
   com.sun.jna.platform.dnd.DragHandler               -> java.util.logging.Level                            not found
   com.sun.jna.platform.dnd.DragHandler               -> java.util.logging.Logger                           not found
   com.sun.jna.platform.dnd.DropHandler               -> java.util.logging.Level                            not found
   com.sun.jna.platform.dnd.DropHandler               -> java.util.logging.Logger                           not found
   com.sun.jna.platform.win32.DBT$DEV_BROADCAST_DEVICEINTERFACE -> java.util.logging.Logger                           not found
   com.sun.jna.platform.win32.DdemlUtil$DdeAdapter    -> java.util.logging.Level                            not found
   com.sun.jna.platform.win32.DdemlUtil$DdeAdapter    -> java.util.logging.Logger                           not found
   com.sun.jna.platform.win32.User32Util$MessageLoopThread -> java.util.logging.Level                            not found
   com.sun.jna.platform.win32.User32Util$MessageLoopThread -> java.util.logging.Logger                           not found
   com.sun.jna.platform.win32.W32FileMonitor          -> java.util.logging.Level                            not found
   com.sun.jna.platform.win32.W32FileMonitor          -> java.util.logging.Logger                           not found
   com.sun.jna.platform.win32.Win32Exception          -> java.util.logging.Level                            not found
   com.sun.jna.platform.win32.Win32Exception          -> java.util.logging.Logger                           not found
   com.sun.marlin.MaskMarlinAlphaConsumer             -> sun.misc.Unsafe                                    JDK removed internal API
   com.sun.marlin.OffHeapArray                        -> sun.misc.Unsafe                                    JDK removed internal API
   com.sun.marlin.OffHeapArray$1                      -> sun.misc.Unsafe                                    JDK removed internal API
   com.sun.marlin.Renderer                            -> sun.misc.Unsafe                                    JDK removed internal API
   com.sun.marlin.RendererNoAA                        -> sun.misc.Unsafe                                    JDK removed internal API
   impl.org.controlsfx.spreadsheet.CellView           -> java.util.logging.Logger                           not found
   javafx.fxml.FXMLLoader                             -> javax.script.Bindings                              not found
   javafx.fxml.FXMLLoader                             -> javax.script.ScriptEngine                          not found
   javafx.fxml.FXMLLoader                             -> javax.script.ScriptEngineFactory                   not found
   javafx.fxml.FXMLLoader                             -> javax.script.ScriptEngineManager                   not found
   javafx.fxml.FXMLLoader                             -> javax.script.SimpleBindings                        not found
   javafx.fxml.FXMLLoader$Element                     -> javax.script.ScriptEngine                          not found
   javafx.fxml.FXMLLoader$ScriptElement               -> javax.script.Bindings                              not found
   javafx.fxml.FXMLLoader$ScriptElement               -> javax.script.Compilable                            not found
   javafx.fxml.FXMLLoader$ScriptElement               -> javax.script.CompiledScript                        not found
   javafx.fxml.FXMLLoader$ScriptElement               -> javax.script.ScriptContext                         not found
   javafx.fxml.FXMLLoader$ScriptElement               -> javax.script.ScriptEngine                          not found
   javafx.fxml.FXMLLoader$ScriptElement               -> javax.script.ScriptEngineFactory                   not found
   javafx.fxml.FXMLLoader$ScriptElement               -> javax.script.ScriptEngineManager                   not found
   javafx.fxml.FXMLLoader$ScriptElement               -> javax.script.ScriptException                       not found
   javafx.fxml.FXMLLoader$ScriptEventHandler          -> javax.script.Bindings                              not found
   javafx.fxml.FXMLLoader$ScriptEventHandler          -> javax.script.Compilable                            not found
   javafx.fxml.FXMLLoader$ScriptEventHandler          -> javax.script.CompiledScript                        not found
   javafx.fxml.FXMLLoader$ScriptEventHandler          -> javax.script.ScriptContext                         not found
   javafx.fxml.FXMLLoader$ScriptEventHandler          -> javax.script.ScriptEngine                          not found
   javafx.fxml.FXMLLoader$ScriptEventHandler          -> javax.script.ScriptException                       not found
   org.controlsfx.control.cell.MediaImageCell         -> javafx.scene.media.Media                           not found
   org.controlsfx.control.cell.MediaImageCell         -> javafx.scene.media.MediaPlayer                     not found
   org.controlsfx.control.cell.MediaImageCell         -> javafx.scene.media.MediaView                       not found
   org.controlsfx.control.spreadsheet.SpreadsheetView -> java.util.logging.Level                            not found
   org.controlsfx.control.spreadsheet.SpreadsheetView -> java.util.logging.Logger                           not found
   org.controlsfx.control.tableview2.FilteredTableView -> java.util.logging.Level                            not found
   org.controlsfx.control.tableview2.FilteredTableView -> java.util.logging.Logger                           not found

Now I would expected to get the jdk modules like java.base, java.desktop, etc but instead I got this.

My idea is to print the list of all the needed jdk modules that I can then use in jlink to generate a custom runtime.

Then, I can just run my application with the usual $MY_CUSTOM_JVM/bin/java -jar mouseMove-1.0.jar

My question are:

Thanks

Updated 10/06/2023: added the project pom.xml

<?xml version="1.0" encoding="UTF-8"?>

4.0.0

<groupId>com.mouse.move</groupId>
<artifactId>mouseMove</artifactId>
<version>1.0</version>

<properties>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <javafx.version>21</javafx.version>
    <jna.version>5.13.0</jna.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-base</artifactId>
        <version>${javafx.version}</version>
    </dependency>
    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-controls</artifactId>
        <version>${javafx.version}</version>
    </dependency>
    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-fxml</artifactId>
        <version>${javafx.version}</version>
    </dependency>
    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-graphics</artifactId>
        <version>${javafx.version}</version>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-core</artifactId>
        <version>1.3.5</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>2.0.4</version>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.3.5</version>
    </dependency>
    <dependency>
        <groupId>net.java.dev.jna</groupId>
        <artifactId>jna</artifactId>
        <version>${jna.version}</version>
    </dependency>
    <dependency>
        <groupId>net.java.dev.jna</groupId>
        <artifactId>jna-platform</artifactId>
        <version>${jna.version}</version>
    </dependency>
    <dependency>
        <groupId>org.controlsfx</groupId>
        <artifactId>controlsfx</artifactId>
        <version>11.1.2</version>
    </dependency>
</dependencies>

<build>
    <finalName>${artifactId}-${version}</finalName>
    <plugins>

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.10.1</version>
            <configuration>
                <source>21</source>
                <target>21</target>
                <compilerArgs>--enable-preview</compilerArgs>
            </configuration>
        </plugin>

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.4.1</version>
            <configuration>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
                <archive>
                    <manifest>
                        <mainClass>com.mouse.move.MouseMoveMain</mainClass>
                    </manifest>
                </archive>
                <appendAssemblyId>false</appendAssemblyId>
            </configuration>
            <executions>
                <execution>
                    <id>make-assembly</id>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Also, the module info:

module mouse.move {
    requires javafx.graphics;
    requires javafx.controls;
    requires javafx.fxml;
    requires org.controlsfx.controls;
    requires com.sun.jna.platform;
    requires org.slf4j;
    requires com.sun.jna;

    opens com.mouse.move;
}

Now that I am thinking, the right question would be: can you mix a standard java maven program with modules? That is extract from your written classes + all the maven dependencies the jdk modules used so that you can then build a custom jvm image?


Solution

  • How to properly get the jdk modules for a fat JavaFX jar using jdeps

    Use the --print-module-deps option with jdeps. If the jar being analyzed also includes dependencies on optional code that is not required for your application (as is the case for you), also use --ignore-missing-deps on the resultant jar file.

    For example for your dependencies:

    jdeps --print-module-deps --ignore-missing-deps target/mouseMove-1.0.jar
    

    I get:

    java.base,java.desktop
    

    So if you run your jar from a jlink image build to include the above modules it should work. But of course, it does not. The reason for this is that you have ignored too many missing depenendencies. Specifically those needed for JavaFX. You can see this because lots of javafx classes show up when you try running without --ignore-mssing-deps and those are actually really needed.

    So let's do this again with the javafx modules provided to jdeps for analysis, using javafx modules downloaded as part of the javafx SDK from gluon:

    jdeps --module-path ~/Downloads/javafx-sdk-21/lib --add-modules javafx.graphics,javafx.controls,javafx.fxml --print-module-deps --ignore-missing-deps target/mouseMove-1.0.jar 
    

    Now we get:

    java.base,java.desktop,java.scripting,jdk.unsupported
    

    Build a new image:

    jlink --add-modules java.base,java.desktop,java.scripting,jdk.unsupported --output customjre
    

    Run it:

    customjre/bin/java -jar target/mouseMove-1.0.jar
    

    It works.

    In order for this to work, the unsupported hack of creating an additional class not extending Application that invokes launch on the class extending Application was used, as documented in:

    Zipping it up, it is 30.4mb is size (this was for an OS X x64 image). Your mouseMove-1.0.jar that includes JavaFX, your app code and your dependencies is an additional 13.9mb. By comparison, an Azul JDK FX distribution for the same platform is 88.5mb.


    Additional background information

    The rest of this "answer" is not really an answer to your specific question title. Instead, it addresses some questions that arise when analyzing your question and in comment responses. Other readers (and you) may choose to ignore it.

    Using a fat jar with JavaFX

    I've created the fat jar which works perfectly from console: ( there is however this warning WARNING: Unsupported JavaFX configuration: classes were loaded from 'unnamed module @4efb10bd' )

    While such a configuration can be made to work with JavaFX 21, it means that you are running an unsupported configuration which may not continue to work with future JavaFX distributions. For more information see:

    Making JavaFX modules available

    You can still build a JavaFX application based on fat jar in a supported way, but doing so has some implications:

    1. JavaFX modules should not be included in the JAR.
    2. JavaFX modules should be available to the runtime (either by adding them to the module path via command line switches or the Java runtime image that the application is using).

    Some ways you can make the JavaFX modules available:

    1. Use a pre-built Java runtime that includes them (e.g. Azul JRE FX).
    2. Use the JavaFX SDK, building against that using command line switches to set the module path and add modules (as documented at openjfx.io) AND, when you ship copying the SDK jars and native libraries to a location in your deployment package.
    3. Use the JavaFX modules from maven (unlike the JavaFX SDK jars, the JavaFX maven jars also include and self-deploy native JavaFX components), and when you ship copy those to your deployment package.

    To get the JavaFX deployment modules into your deployment package, you can either:

    1. Copy them there (e.g. using a maven assembly) OR
    2. You can use jlink to link them into an image OR
    3. You can use a prebuilt-runtime like Azure JRE FX that already includes the JavaFX modules.

    One disadvantage of using a prebuilt-runtime is the overall deployment will be larger as the prebuilt runtime may include packages you don't need (for instance if you don't use the javafx.web module, you don't need it, but it is quite large because it includes an entire Webkit implementation and JavaScript virtual machine). For many installations this additional size won't matter that much.

    Note that JavaFX current depends on the AWT and Swing toolkits, so any runtime you ship that inclues JavaFX, will also include those toolkits.

    So, one approach (which is kind of what you are initially trying in your question), would be to create a custom Java runtime that includes JavaFX.

    Using jlink to create an image or runtime

    Now, if you are going to be creating a custom runtime, in addition to including base JRE modules and JavaFX modules, you could also include additional 3rd party modules required by your application, and your application module, if your application is modular. If you do this, then you don't need and should not create a fat jar. Instead, you should specify a correct and complete module-info.java for your application and link all the required modules into the image using jlink.

    When you do this jlink, will traverse the module graph and find the minimal set of modules needed to run your application and link them into the resultant runtime, creating the smallest possible runtime needed to execute your application. You do not need to use jdeps to determine which modules to links, jlink will find and link all of the required modules that were in the module graph and on the module path.

    If you are using maven, the easiest way to accomplish this is to run the maven-javafx-plugin jlink target, which will create an image with the required JDK, JavaFX, application 3rd party dependencies and application modules, create a shell script to launch the application and zip the complete image up into a zip file for distribution. To use it, your end user can unzip the distribution and then run the application launcher shell script from the command line.

    unzip app.zip
    bin/app
    

    If jlink is run with the --strip-native-commands it won't include the Java command (instead your app is run using the generated shell script). But, if you don't use that switch, then you will get a java command which can be used to execute Java code the same way as for any other java runtime. Then you could do as you ask in your question:

     $MY_CUSTOM_JVM/bin/java -jar mouseMove-1.0.jar
    

    If that is what you really wanted. But, if your application is already in the custom image, instead of bundling a jar you could run it using:

     java [options] -m module[/mainclass] [args ...]
    

    This is how the prebuilt launcher works, for example, on my machine (OS X) the shell script for the app launcher is:

    #!/bin/sh
    JLINK_VM_OPTIONS=
    DIR=`dirname $0`
    $DIR/java $JLINK_VM_OPTIONS -m com.example.jlinkdem/com.example.jlinkdem.HelloApplication "$@" 
    

    Automatic modules

    A restriction on jlink today is that the tool cannot link automatic modules. That means that for jlink to be able to link your entire project, every transitive dependency of the project needs to have a well-defined module-info. Unfortunately, many important 3rd party jar files do not include a module-info and cannot be linked by jlink. This means you need to exclude the non-modular jars from the jlink process, package them separately and ensure they are added to the classpath or modulepath. Tools like jpackage or complex maven assemblies may assist with this (discussion of how to do this is out of scope for my discussion here).

    Understanding the issue with fat jars and the Java module system

    When you create a fat jar using a tool such as the maven shade plugin or maven assembly plugin jar-with-dependencies option, all of the code from each of the dependencies is copied into a single jar file. Normally, that is fine if java modules are not involved, as all of the code in each jar would normally be added to the classpath.

    But with modular jars, this is an issue. Each modular jar has, at its root a module-info which defines the module. If many jars are shaed into one, there is no way to combine this module-info into a single value which makes sense using the current Java module technology. So all of the module info in the dependent jars is lost and, your own code cannot be modular either because its module-info would depend on module-info which would have been provided in the dependent jars and no longer exists.

    Hence Slaw's recommendation:

    Don't include JavaFX in the fat JAR. Instead, include JavaFX in the custom run-time image you're trying to create. See this Q&A for more information regarding the warning.

    And my recommendation:

    You can’t jlink a “fat jar”. You can only jlink modules (jars which include module-info or jmods). When jlinking modules from the base jdk, jlink will use the jmods provided with the jdk (the jlink man page describes this process).

    And also Slaw's description of the related issues:

    There are a couple things to note about this:

    1. The jlink tool can only work with explicit modules (i.e., the dependency must have a module-info descriptor; automatic modules won't work).
    2. Your own code has a module-info descriptor, but you're trying to create a fat JAR file. Fat JARs are incompatible with modules, at least with the JAR File Specification in its current form (with custom module layers and/or class loaders, you can work around this problem—not necessarily trivial though).
    3. Named modules (i.e., code on the module-path) cannot directly reference code in the unnamed module (i.e., code on the class-path). If your code directly relies on any non-modular dependencies, then you cannot put your own code in the custom run-time image (for that reason, and because your code would have to be modular with requires on automatic modules, hitting point 1 in my previous comment). However, the unnamed module can use named modules. So, you can put modular dependencies in the custom run-time image, while having everything else on the class-path (e.g., a fat JAR).

    Using a pre-created Java runtime to run another jar

    As noted by Slaw in comment:

    I think the OP's goal is to create a fat JAR, and then separately jlink a custom run-time image that includes only the Java/JDK modules needed by the fat JAR. They're trying to use jdeps to determine which Java/JDK modules are needed.

    For which I recommend some of these options:

    1. Building a custom runtime.

    I'd suggest following openjfx.io instructions to create a custom JDK + JavaFX Image at openjfx.io, but don't supply the --bind-services flag which may include a lot of unnecessary stuff. Then you get a minimal runtime upon which you could use a JavaFX app.

    In the fat jar, don't include JavaFX components as noted by Slaw. If you need https or tls support, then also link in the cryptoki module. If something else breaks on execution due to a missing module you can add the additional module. This may occur because you use optional services such as cryptoki (even if you didn't know that you relied on such services) which a minimal jlink image (or even a jdeps code analysis) will not reveal as such services are loaded and used optionally at runtime, so the static linker won't know they are needed and to link them unless you explicitly tell it you need them.

    To minimize the size of the generated image, you would also probably want to supply a --launcher and set various options to remove unnecessary components (such as --no-header-files, --no-man-pages, --strip-debug, --strip-native-commands, etc).

    Include required locales with --include-locales, otherwise you will lose support for translation of some locale information.

    While you can do the above from the command line, the maven-jlink-plugin can help if you use maven, or, if you use gradle, the badass-runtime-plugin can be used to package your app, as it performs a lot of dependency checks and configuration steps I mentioned for you, rather than having to manually specify the values at the command line. But, probably, either way would work.

    1. Using a prebuilt runtime

    For example azul zulu jre fx. It would include some modules you don't need but would may not really matter.

    Regarding your dependencies and jdeps output

    javax.mail is obsolete. It might work OK with Java 9+ modules, or it may not (I don't know). It is still best to use a modern Java mail system (Angus Mail is the javax.mail replacement). As you are using logback, this is detailed in the baeldung article: "Sending Emails with Logback".

    However, you probably aren't sending emails with logback anyway, similarly you are also probably not using a servlet filter or binding to a naming directory using jndi while using logback. Those are all dependencies showing up in your jdeps analysis. This is because logback is a pluggable implementation. The core classes are compiled against those other libraries and can use them if it logback is configured to use them and the libraries are available at runtime. But if you don't need them you don't need to supply them. Therefore the jdeps analysis that you have run ends up being a bit confusing as it is referencing many potential dependencies which you don't actually need for your application and can just ignore.

    FAQ

    I am trying to see which jdk modules I am using in the jar so I can use jlink to create a custom runtime. The project is done in maven so I have other jars beside javafx ( apache, logging, etc ).

    I do recommend if you do this that you use the most recent stable versions of all software (for instance logback 1.4.x based on jakarta, not obsolete jee software and slf4j 2.x which is compatible with java modules with well-defined module-info, unlike older slf4j versions).

    If all the modules are well formed (they include a module-info), and your own project is modular (provides a module-info) this is actually a reasonably straightforward thing to do. You do not need jdeps for it, jlink will determine the minium modules needed and create an appropriate image. It might end up too minimum because it may exclude some optional services that your application may need to function, in which case you should ensure that you have those needed services specified as runtime dependencies in your maven dependency setup and require (or use) those services in your module info. See understanding modules for more info on consuming services.

    If the modules are not well-formed or you have a non-modular application, then you could use jdeps to determine the modules required, the --print-module-deps option you set should work to do this, if you supply all other arguments correctly. For me, when I analyze a non-modular jar for dependencies, this option will determine a comma separated list of modules that can be passed to a jlink command. To do so, I set the module path and classpath arguments to jdeps so it knows where the dependent jars are, provide the jar to be analyzed as input and use the --ignore-missing-deps command so that jdeps doesn't spam with warnings about optional services that aren't being used (such as the unused java mail and servlet api jars shown in your jdeps output).

    requires com.sun.jna;

    This implies that you are using jna for native access. That implies you have native components like DLLs or .so files. Which you can use those within the Java module system. Doing so is a complex and advanced topic which I will not address here.

    Also jna is an autoamtic module that cannot be jlinked:

    Error: automatic module cannot be used with jlink: com.sun.jna from file:///Users/<username>/.m2/repository/net/java/dev/jna/jna/5.13.0/jna-5.13.0.jar
    

    I would like to know what jdk modules does logback use, jna, etc. And maybe in the future I will have more. If it's possible of course.

    logback has a module info defined, it tells you what modules it uses.

    Here are the requires portions:

    requires transitive java.xml;
    requires static java.sql;
    
    // required by the optional SMTPAppenderBase component
    requires static java.naming;
    
    requires static janino;
    requires static commons.compiler;
    
    // transitive _imposes_ the presence of jakarta.mail on downstream users,
    // let them declare it if they need it
    requires static jakarta.mail;
    
    // jakarta.servlet 5.0 is not modular
    requires static jakarta.servlet;
    
    // optionally require jansi
    requires static org.fusesource.jansi;
    

    You can see that most of the requirements are requires static which makes them optional dependencies. You can deploy a logback app without supplying those dependent libraries (modules) if you don't need them - most people won't want most or all of those additional dependencies.

    You can see what the actual dependencies are using the following command:

    jdeps --print-module-deps --ignore-missing-deps logback-core-1.4.11.jar
    

    Which outputs:

    java.base,java.xml
    

    So there you have the list of required dependencies. That is what jlink will include transitively when you link the the logback core module with anything else.

    Now if you also needed some optional dependencies for your application, you could specify that in your application module-info (e.g. `uses , then run the same jdeps analysis on your application jar file with the module-info and it will show you what the dependencies are). Or you can add modules at the command line for jdeps, for instance to add a jndi naming interface so that lgoback could use it:

    jdeps --print-module-deps --ignore-missing-deps --add-modules java.naming logback-core-1.4.11.jar
    

    Then it shows you will need:

    java.base,java.security.sasl,java.xml