无法 运行 JAVAFX .jar 文件(发生许多错误)

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

我在为我的 JAVAFX 程序创建 .jar 文件时遇到问题。

重要信息:

JAVA外汇版本:17

JAVA 版本: 17

IDE: Intellij

项目使用 Maven

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

文件结构:

模块文件:

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 文件:

<?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>

我像这样创建了一个 jar :

当我 运行 这样的罐子时:

我收到以下错误:

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

当我从终端使用命令 java --module-path C:\Users\aenas\Desktop\javafx-sdk-17.0.1 --add-modules javafx.fxml,javafx.graphics,java.sql -jar DevicesInfoCards.jar

运行 时

我收到以下错误

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

并且当我尝试以下命令时:

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

我收到以下错误

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

我在 SO 中看过很多教程并阅读了很多答案,但我没有得到任何新东西。

解决方案之一是将以下内容添加到 POM 文件中:

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

最后一个错误没能解决,虽然我确实用java11编译了程序,但是还是出现了同样的错误。

我这样做了(将代码添加到 POM 文件中),但我也遇到了以下错误:

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

我也尝试用main方法创建一个新的class,并让它调用Main cless,但这没有用,我得到了以下错误:

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

虽然我已经将 POM 文件中的所有 <mainclass></mainclass> tegs 更改为正确的新主 class,但我仍然遇到相同的错误。

预先感谢您的帮助;

UPDATE

我所做的是删除了模块信息文件,从 POM 文件中删除了所有 javafx 依赖项,所以我的 POM 现在看起来像这样:

<?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>

当我 运行 mvn package 我得到以下输出:

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] ------------------------------------------------------------------------

但是当我 运行 java -jar DevicesHistoryCards_Maven2.jar 我得到以下信息: Error: Unable to access jarfile DevicesHistoryCards_Maven.jar

为什么我不能访问它,它是在哪里创建的?

尝试使用调用应用程序 class 的主要方法的主要方法创建一个新的 Class 并将其用作入口点。

此答案提供了两种打包和分发应用程序的备选方案,不推荐使用一种(创建 fat jar 文件),推荐使用另一种(使用 jlink 或 jpackage)。

相关问题

我认为问题的核心是:

因为在副本中,您是:

  1. 使用 Maven。
  2. 使用 JavaFX。
  3. 希望创建一个可执行的 jar。

但是,我添加了一个答案来概述您必须在项目中更改才能使其正常工作的具体事项。

不推荐的方法:Fat JAR

创建 fat jar 不是当前支持的打包 JavaFX 应用程序的方法。

JavaFX 的 fat jar 模板由 openjfx.io project 提供。

pom.xml project file在这里。

如果不清楚以下步骤,请研究 JavaFX 的 maven 着色和示例 openjfx.io 项目的链接问题。

将项目转换为可以打包为 fat jar 的步骤:

  1. 在 pom.xml 文件中为您的应用程序定义所有必需的 JavaFX 依赖项。

    • Maven 将传递导入,因此您不需要直接依赖低级工件,例如 javafx-base,只需要 higher-level 那些 javafx-controls 和 javafx-fxml (如果你使用那个)。
  2. 应该是一个non-modular项目(删除你的module-info.java)

  3. 需要一个单独的launcher class(创建一个)

  4. 它需要使用 maven shade 插件合并 jar(使用那个)

  5. 要使其跨平台,您需要提供class化的依赖项(添加它们)

  6. 要支持 M1 macs,您需要

    • 额外的 classifier 依赖项 mac-aarch64(添加那个)
    • JavaFX 17.0.2+(升级到那个版本)。
  7. 您需要使用 Maven 依赖项而不是 JavaFX SDK(您可以删除 SDK)。

    • maven 工件与 SDK 中提供的 jar 不同。
    • maven 工件包含本机代码,SDK 中的 jar 不包含本机代码,本机代码在 SDK 分发中单独的本机库文件中提供。
    • 通过单独下载,您可以获得包含java代码和本机代码的jmod文件,但这些文件与Maven shade进程不兼容,可用于jlink进程(如Maven 工件)。
  8. 使用 transformer in the shade plugin 指定主要 class,而不是使用 maven-jar-plugin(您应该删除 maven-jar-plugin 部分)。

  9. 使用 mvn package 打包您的应用程序,不要在 IDE

    中使用 built-in 工件生成器
    • 不要使用 Idea 或 Eclipse 工件生成系统。
    • IDE 工件生成系统当前不支持正确生成包含 JavaFX 运行 时间组件的可执行 jar,它们会生成工件,但如果您尝试执行它们。

    mvn package 步骤将生成警告,但它可能仍然有效:

     [WARNING] Discovered module-info.class. Shading will break its strong encapsulation.
    
  10. 到运行只需使用以下命令,别无其他:

    java -jar <yourjar>.jar
    

    这假定用户正确:

    • 安装了兼容的 JRE 版本。
    • 配置系统路径以包含包含相应 java 二进制文件的目录。
    • 用户的当前目录是包含阴影 jar 的目录。

    执行步骤将生成警告,但它可能仍然有效:

    WARNING: Unsupported JavaFX configuration: classes were loaded from 'unnamed module @14c24f4c'
    
  11. 不要再为任何东西指定 JavaFX SDK 的路径,不再需要支持此开发管道。

  12. 不要指定 module-paths 因为您只是 运行 将您的应用程序及其依赖项从 class 路径(即您的 jar 文件)中删除。

    • 只有核心 JRE 在模块路径上,这是隐含的,因为核心 JRE classes 在 JRE 模块引导路径上。
  13. 您正在为 Java 17 编译为 Java 17 字节码(您的 maven-compiler-plugin 源和目标是 17)

    • 所以你 必须 运行 它针对 Java 17+ 版本,否则它不会工作,你会得到字节码错误。

我可能漏掉了一个步骤,但是,如果我没有漏掉,而你做了所有这些,它将适用于 JRE/JavaFX 17.0.2。生成的 jar 可以在兼容平台上使用兼容的 pre-installed JRE 执行。

推荐方法:jlink 或 jpackage

建议构建 jlink 镜像:

  1. 使用javafx-maven-pluginmvn javafx:jlink命令
    • Assemble 至通过为 javafx-maven-plugin.
    • 设置 jlinkZipName 参数来压缩
    • 确保您有一个完全模块化的应用程序:
      • 在您的应用中定义一个 module-info.java 文件。
      • 确保所有依赖项也定义了一个 module-info.java 文件。
  2. 到 运行,解压缩 zip 并使用 jlink 创建的启动脚本。

或者,您可以使用 jpackage 创建本机安装程序,例如:

使用 jlink 或 jpackage 创建分布是受支持的配置。对于开发者来说,创建jlink镜像比创建fat jar更简单可靠。

应用程序的用户使用应用程序更容易、更可靠,因为除了您的应用程序之外,他们不需要获取和安装兼容的 Java 运行时间。

外包资源

有关包装的更多信息,请参见:

常见问题解答

deleted all javafx dependances from the POM file

不要那样做,将您的应用程序使用的 JavaFX 依赖项包含在 pom.xml 文件中(以及任何必需的第 3 方依赖项)。

您不需要包含 Java您不使用的 FX 依赖项

您不需要显式列出将被传递导入的依赖项,例如 javafx-base.

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

当您 运行 打包步骤时,这会列在您的日志文件中:

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

它创建了带阴影和不带阴影的罐子,然后用带阴影的罐子替换了带阴影的罐子。

要查看 jar 文件的内容,您可以 运行:

jar tvf <your-jar-file>.jar

在你的例子中做:

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

里面会有很多东西。该 jar 将包含您的应用程序代码、来自您的依赖库的所有代码、所有 JavaFX java 代码和 JavaFX 本机代码(例如 Windows DLL) class已修改 Java您在 pom.xml 中定义的 FX 依赖项以匹配您的目标分发平台。

如果您使用 openjfx fat jar sample pom.xml 中的阴影定义,它会对阴影 jar 使用 classifier 并将其输出到单独的目录中,因此阴影 jar 不会覆盖目标 jar而是在 <project directory>/shade 文件夹中创建一个单独的 jar。

如果您不想,则不需要对阴影罐使用 class 转换器。

有关详细信息,请参阅:

  • 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

克隆 OpenJFX 示例项目以验证您的环境

如果您仍然有问题,请从 git 克隆 openjfx sample project 并尝试构建它,以确保在使用已知的良好项目时,您可以使打包在您的环境中正常工作。