Search code examples
javamavenintellij-ideajavafxexecutable-jar

Can not run JAVAFX .jar File (many errors occurred)


I am having a problem creating a .jar file for my JAVAFX Program.

important info:

JAVAFX Version: 17

JAVA Version: 17

IDE: Intellij

Project Uses Maven

..................................................................................................................................................................................................................................................

file structure:

enter image description here

module File:

module A_DevicesInfoCardsManager {
    requires javafx.controls;
    requires javafx.fxml;
    requires javafx.graphics;
    requires java.sql;
    
    opens application to javafx.graphics, javafx.fxml, javafx.base, javafx.controls,java.sql;
}

POM File:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>application</groupId>
    <artifactId>DevicesInfoCards</artifactId>
    <version>1.0-SNAPSHOT</version>
    <name>DevicesInfoCards</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <junit.version>5.8.1</junit.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-controls</artifactId>
            <version>17.0.1</version>
        </dependency>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-fxml</artifactId>
            <version>17.0.1</version>
        </dependency>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-web</artifactId>
            <version>17.0.1</version>
        </dependency>
        <dependency>
            <groupId>org.controlsfx</groupId>
            <artifactId>controlsfx</artifactId>
            <version>11.1.0</version>
        </dependency>
        <dependency>
            <groupId>com.dlsc.formsfx</groupId>
            <artifactId>formsfx-core</artifactId>
            <version>11.3.2</version>
            <exclusions>
                <exclusion>
                    <groupId>org.openjfx</groupId>
                    <artifactId>*</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>net.synedra</groupId>
            <artifactId>validatorfx</artifactId>
            <version>0.1.13</version>
            <exclusions>
                <exclusion>
                    <groupId>org.openjfx</groupId>
                    <artifactId>*</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.kordamp.ikonli</groupId>
            <artifactId>ikonli-javafx</artifactId>
            <version>12.2.0</version>
        </dependency>
        <dependency>
            <groupId>org.kordamp.bootstrapfx</groupId>
            <artifactId>bootstrapfx-core</artifactId>
            <version>0.4.0</version>
        </dependency>
        <dependency>
            <groupId>eu.hansolo</groupId>
            <artifactId>tilesfx</artifactId>
            <version>11.48</version>
            <exclusions>
                <exclusion>
                    <groupId>org.openjfx</groupId>
                    <artifactId>*</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>17</source>
                    <target>17</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.openjfx</groupId>
                <artifactId>javafx-maven-plugin</artifactId>
                <version>0.0.8</version>
                <executions>
                    <execution>
                        <!-- Default configuration for running with: mvn clean javafx:run -->
                        <id>default-cli</id>
                        <configuration>
                            <mainClass>application/application.Main
                            </mainClass>
                            <launcher>app</launcher>
                            <jlinkZipName>app</jlinkZipName>
                            <jlinkImageName>app</jlinkImageName>
                            <noManPages>true</noManPages>
                            <stripDebug>true</stripDebug>
                            <noHeaderFiles>true</noHeaderFiles>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

I created a jar Like this :

enter image description here

when I ran the jar like this:

enter image description here

I got the following error:

Error: JavaFX runtime components are missing, and are required to run this application

and when I ran it from the terminal using the command java --module-path C:\Users\aenas\Desktop\javafx-sdk-17.0.1 --add-modules javafx.fxml,javafx.graphics,java.sql -jar DevicesInfoCards.jar

I got the following error

Error occurred during initialization of boot layer
java.lang.module.FindException: Module javafx.graphics not found

and When I tried the following command:

 java --module-path C:\Users\aenas\Desktop\javafx-sdk-17.0.1 -jar DevicesInfoCards.jar

I got the following Error

Error: LinkageError occurred while loading main class application.Main
        java.lang.UnsupportedClassVersionError: application/Main has been compiled by a more recent version of the Java Runtime (class file version 61.0), this version of the Java Runtime only recognizes class file versions up to 55.0

I have seen many tutorials and read many answers here in SO, but I did not get anything new.

one of the sollutions was to add the following to he POM file:

<packaging>jar </packaging>


            <plugin>
                <!-- Build an executable JAR -->
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.2.0</version>
                <configuration>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <classpathPrefix>lib/</classpathPrefix>
                            <mainClass>application.Main</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>

I could not solve the last error, although I did compile the program using java 11, but the same error occurred.

I did that (adding the code to the POM file) but I also got the following error:

Error: Could not find or load main class application.Main
Caused by: java.lang.NoClassDefFoundError: javafx/application/Application

I also tried to create a new class with a main method, and let it call the Main cless, but this did not work, and I got the following error:

no main manifest attribute, in C:\Users\aenas\IdeaProjects\demo2\DevicesHistoryCards_Maven\out\artifacts\DevicesHistoryCards_Maven_jar\DevicesHistoryCards_Maven.jar

Process finished with exit code 1

although I have changed all <mainclass></mainclass> tegs in my POM file to the correct new main class, I still getting the same error.

Thank you in advance for your help;

UPDATE

what I did is that I deleted the module info file, deleted all javafx dependances from the POM file, so my POM looks like that now:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>application</groupId>
    <artifactId>DevicesHistoryCards_Maven</artifactId>
    <version>1.0-SNAPSHOT</version>
    <name>DevicesHistoryCards_Maven</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <junit.version>5.8.1</junit.version>
    </properties>

    <dependencies>





        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>



            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>11</source>
                    <target>11</target>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>3.2.4</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <transformers>
                                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <mainClass>application.MainLauncher</mainClass>
                                </transformer>
                            </transformers>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <groupId>org.openjfx</groupId>
                <artifactId>javafx-maven-plugin</artifactId>
                <version>0.0.8</version>
                <executions>
                    <execution>
                        <!-- Default configuration for running with: mvn clean javafx:run -->
                        <id>default-cli</id>
                        <configuration>
                            <mainClass>
                                application.MainLauncher
                            </mainClass>
                            <launcher>app</launcher>
                            <jlinkZipName>app</jlinkZipName>
                            <jlinkImageName>app</jlinkImageName>
                            <noManPages>true</noManPages>
                            <stripDebug>true</stripDebug>
                            <noHeaderFiles>true</noHeaderFiles>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

and when I ran mvn package I got the following output:

PS C:\Users\aenas\IdeaProjects\demo2\DevicesHistoryCards_Maven2> mvn package
[INFO] Scanning for projects...
[INFO]
[INFO] ---------------< application:DevicesHistoryCards_Maven >----------------
[INFO] Building DevicesHistoryCards_Maven 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ DevicesHistoryCards_Maven ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 6 resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ DevicesHistoryCards_Maven ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ DevicesHistoryCards_Maven ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory C:\Users\aenas\IdeaProjects\demo2\DevicesHistoryCards_Maven2\src\test\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ DevicesHistoryCards_Maven ---
[INFO] No sources to compile
[INFO]
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ DevicesHistoryCards_Maven ---
[INFO] No tests to run.
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ DevicesHistoryCards_Maven ---
[INFO]
[INFO] --- maven-shade-plugin:3.2.4:shade (default) @ DevicesHistoryCards_Maven ---
[INFO] Replacing original artifact with shaded artifact.
[INFO] Replacing C:\Users\aenas\IdeaProjects\demo2\DevicesHistoryCards_Maven2\target\DevicesHistoryCards_Maven-1.0-SNAPSHOT.jar with C:\Users\aenas\IdeaProjects\demo2\DevicesHistoryCards_Maven2\target\DevicesHistoryCards_Maven-1.0-SNAPSHOT-shaded.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  4.692 s
[INFO] Finished at: 2022-02-17T13:40:42+03:00
[INFO] ------------------------------------------------------------------------

but when I ran java -jar DevicesHistoryCards_Maven2.jar I got the following: Error: Unable to access jarfile DevicesHistoryCards_Maven.jar

so why cant I access it, and where is it created ?


Solution

  • This answer provides two alternatives for packaging and distributing your application, one (creating a fat jar file) is not recommended, the other (using jlink or jpackage) is recommended.

    Related Question

    I believe the question is, at its core, a duplicate of:

    because, as in the duplicate, you are:

    1. Using Maven.
    2. Using JavaFX.
    3. Hoping to create an executable jar.

    However, I have added an answer to outline specific things you must change in your project to get it to work.

    Not Recommended Approach: Fat JAR

    Creating a fat jar is not a currently supported way to package a JavaFX application.

    A template for a fat jar with JavaFX is provided by the openjfx.io project.

    The pom.xml project file is here.

    If unclear about the steps below, study the linked question on maven shading of JavaFX and the sample openjfx.io project.

    Steps to transform your project to one which can be packed as a fat jar:

    1. Define all of the required JavaFX dependencies for your applicatoin in the pom.xml file.

      • Maven will import transitively, so you don't need direct dependencies on low level artifacts such as javafx-base, just the higher-level ones like javafx-controls and javafx-fxml (if you use that).
    2. It should be a non-modular project (delete your module-info.java)

    3. It requires a separate launcher class (create one)

    4. It requires merging of jars using the maven shade plugin (use that)

    5. To make it cross platform you need to provide classified dependencies (add them)

    6. To support M1 macs, you need

      • An additional classifier dependency mac-aarch64 (add that)
      • JavaFX 17.0.2+ (upgrade to that).
    7. You need to use Maven dependencies not the JavaFX SDK (you can delete the SDK).

      • The maven artifacts are different from the jars shipped in the SDK.
      • The maven artifacts include native code, the jars in the SDK do not, native code is provided in separate native library files in the SDK distribution.
      • Through a separate download, you can obtain jmod files that include java code and native code, but those aren't compatible with the Maven shade process, those can be used for the jlink process (as can the maven artifacts).
    8. Specify the main class using a transformer in the shade plugin, not using the maven-jar-plugin (you should remove the maven-jar-plugin section).

    9. Use mvn package to package your application, do not use the built-in artifact generators in an IDE

      • Do not use the Idea or Eclipse artifact generation systems.
      • The IDE artifact generation systems do not currently support correctly generating executable jars which include JavaFX runtime components, they will generate artifacts, but they will exhibit errors if you try to execute them.

      The mvn package step will generate a warning, though it will likely still work:

       [WARNING] Discovered module-info.class. Shading will break its strong encapsulation.
      
    10. To run just use the following command and nothing else:

      java -jar <yourjar>.jar
      

      This assumes the user has correctly:

      • Installed a compatible JRE version.
      • Configured the system path to include the directory containing the appropriate java binary file.
      • The user's current directory is the directory containing the shaded jar.

      The execution step will generate a warning, though it will likely still work:

      WARNING: Unsupported JavaFX configuration: classes were loaded from 'unnamed module @14c24f4c'
      
    11. Don't specify paths to the JavaFX SDK for anything anymore, it is no longer needed to support this development pipeline.

    12. Don't specify module-paths because you are just running your app and its dependencies off the classpath (which is your jar file).

      • only the core JRE is on the modulepath and that is implicit as the core JRE classes are on the JRE module boot path.
    13. You are compiling for Java 17 to Java 17 bytecode (your maven-compiler-plugin source and target are 17)

      • so you must run it against a Java 17+ version or it won't work, you will get byte code errors.

    I may have missed a step, but, if I did not, and you do all that, it will work for JRE/JavaFX 17.0.2. The resultant jar can be executed using a compatible pre-installed JRE on a compatible platform.

    Recommended Approach: jlink or jpackage

    It is recommended instead to build a jlink image:

    1. Use the javafx-maven-plugin mvn javafx:jlink command
      • Assemble to a zip by setting the jlinkZipName parameter for the javafx-maven-plugin.
      • Ensure you have a completely modular application:
        • Define a module-info.java file in your app.
        • Ensure that all of your dependencies also define a module-info.java file.
    2. To run, extract the zip and use the jlink created launch script.

    OR, you can use jpackage to create a native installer, see for instance:

    Creating distributions using jlink or jpackage are supported configurations. It is easier and more reliable for a developer to create a jlink image than to create a fat jar.

    It is easier and more reliable for users of the application to use the application as they do not need to obtain and install a compatible Java runtime in addition to your application.

    External Packaging Resources

    Further information on packaging is provided in:

    FAQ

    deleted all javafx dependances from the POM file

    Don't do that, include the JavaFX dependencies used by your application in the pom.xml file (and any required 3rd party dependencies).

    You don't need to include JavaFX dependencies you don't use

    You don't need to explicitly list dependencies which will be imported transitively, such as javafx-base.

    where is the .jar file created by the command mvn package

    This is listed in your log file when you run the package step:

    Replacing C:\Users\aenas\IdeaProjects\demo2\DevicesHistoryCards_Maven2\target\DevicesHistoryCards_Maven-1.0-SNAPSHOT.jar with C:\Users\aenas\IdeaProjects\demo2\DevicesHistoryCards_Maven2\target\DevicesHistoryCards_Maven-1.0-SNAPSHOT-shaded.jar
    

    It created both shaded and unshaded jars, then replaced the unshaded jar with the shaded jar.

    To see the contents of a jar file, you can run:

    jar tvf <your-jar-file>.jar
    

    In your example do:

    cd C:\Users\aenas\IdeaProjects\demo2\DevicesHistoryCards_Maven2\target
    jar tvf DevicesHistoryCards_Maven-1.0-SNAPSHOT.jar
    

    There will be lot of stuff in there. The jar will include your app code, all code from your dependent libraries, all the JavaFX java code and the JavaFX native code (e.g. Windows DLLs) for the classified JavaFX dependencies that you defined in your pom.xml to match your target distribution platforms.

    If you use the shade definition from the openjfx fat jar sample pom.xml, it uses a classifier for the shaded jar and outputs it in a separate directory, so the shaded jar does not overwrite the target jar but instead creates a separate jar in a <project directory>/shade folder.

    You don't need to use the classifier for the shaded jar if you don't want to.

    For more info see:

    • attaching the shaded artifact

      By default, the plugin will replace the project's main artifact with the shaded artifact. If both the original and the shaded artifact should be installed/deployed to the repository, one can configure the plugin to attach the shaded artifact as a secondary artifact

    Cloning the OpenJFX Sample Project to verify your environment

    If you are still having issues clone the openjfx sample project from git and try building it to ensure that you can get the packaging to work correctly in your environment when using a known good project.