使用Gradle和IntelliJ为JavaFX构建FatJar时出现NoClassDefFOundError错误

6

我在IntelliJ(2019.2)中使用内置的Gradle支持创建了一个OpenJDK 12项目。为了设计GUI,我使用JavaFX 12。我多次遵循和阅读了设置指南,我在IDE中运行程序没有问题,但是当我尝试构建一个.jar文件以进行分发时出现问题。到目前为止,我还没有找到可行的解决方案,而且我已经搜索了相当多的资料,几乎把头发都搞掉了。当前,当我尝试使用java -jar "jarName".jar运行我的jar文件时,会出现以下错误:

Exception in thread "main" java.lang.NoClassDefFoundError: javafx/application/Application
        at java.base/java.lang.ClassLoader.defineClass1(Native Method)
        at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1016)
        at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:151)
        at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:802)
        at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:700)
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:623)
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
        at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
        at com.CAM.Starter.main(Starter.java:6)
Caused by: java.lang.ClassNotFoundException: javafx.application.Application
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:583)
        at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
        ... 10 more

我尝试将我的主类移动到一个单独的类中,该类不继承Application,这就是导致以上错误的原因。如果不移动我的主类,我会得到另一种错误。
目前我的build.gradle文件如下:
plugins {
    id 'java'
    id 'application'
    id 'org.openjfx.javafxplugin' version '0.0.8'
}

group 'ClassicAddonManager'
version '0.2'
sourceCompatibility = 11

repositories {
    mavenCentral()
}

javafx {
    version = "12.0.2"
    modules = [ 'javafx.controls', 'javafx.fxml' ]
}

dependencies {
    testCompile group: 'junit', name: 'junit', version: '4.12'
    compile 'net.sourceforge.htmlunit:htmlunit:2.13'
    compile group: 'com.google.code.gson', name: 'gson', version: '2.7'
    compile group: 'net.lingala.zip4j', name: 'zip4j', version: '1.2.4'
}

jar {
    manifest {
        attributes 'Main-Class': 'com.CAM.Starter'
    }
    from {
        configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
    }
}

如果我将我的主方法扩展为Application,那么我会得到一个错误,指出找不到我的主类,即使我可以看到它存在于生成的.jar文件中。
我想做的全部内容就是生成一个朋友可运行的文件,而他们没有编程知识。理想情况下,他们可以在不必先安装Java的情况下运行该文件。我知道这应该是可能的,但Gradle对我来说很新,所以我不确定是否这就是导致所有问题的原因。有没有可能有更简单的部署方式?特别是考虑到这是一个独立项目?
编辑
我尝试了指南中的模块化部分。这样做,在构建时我有超过100个错误。它们都是一些相似的东西:
javafx.graphicsEmpty reads package org.xml.sax from both xml.apis and java.xml

请参见 https://openjfx.io/openjfx-docs/#modular,Gradle非模块化项目部分。 - José Pereda
@JoséPereda 我已经阅读并尝试了那个方法。但这样做却带来了另一个问题,我无法生成jar文件。出现了许多错误,例如:javafx.graphicsEmpty从xml.apis和java.xml两个包中读取org.xml.sax包。 - erik p
当你在命令行上运行 java -jar yourfatjar.jar,它是否有效? - José Pereda
@JoséPereda 是的,那个方法完全可行。只有当我双击时才会出现问题。我尝试过调整注册表和默认程序,但都没有用。如果我关闭CMD,GUI也会关闭,这个问题让我束手无策。 - erik p
关于双击,这篇帖子可能会有所帮助。 - José Pereda
1个回答

16

如果你想使用Gradle制作一个Fat Jar而不使用shadow插件,通常会执行以下步骤:

jar {
    manifest {
        attributes 'Main-Class': 'com.CAM.Starter'
    }
    from {
        configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
    }
}

然而,有一个重要的事实: compile 已被弃用,JavaFX插件默认使用 implementation链接

因此,configuration.compile 可能为空,或者至少不包含 JavaFX 类。

解决方法是检查 runtimeClasspath 配置,因为我们会在那里找到所有的类,并且我们可以制作出 Fat Jar 包:

jar {
    manifest {
        attributes 'Main-Class': 'com.CAM.Starter'
    }
    from {
        configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
    }
}

这在OpenJFX文档中已经解释了,https://openjfx.io/openjfx-docs/#modular,非模块化项目章节,gradle子章节。

一旦您获得了您的fat jar,您可以使用以下命令运行它:

java -jar yourFatJar.jar
请注意,双击它是行不通的,如详细说明此处,因此创建一个小批处理文件可能更方便。 更好的解决方案是进行模块化项目并使用jlink创建运行时镜像(它还包括启动器脚本)。您可以将此映像分发给其他甚至没有JDK安装的用户。 使用gradle,您只需包含'org.beryx.jlink'插件,就像在此示例中一样。 您还可以使用jpackage的早期版本来创建和分发安装程序。

1
这可能是需要的(对我来说绝对如此):duplicatesStrategy(DuplicatesStrategy.EXCLUDE) - Macintosh Fan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接