当前位置: 首页 > 知识库问答 >
问题:

Java11和JavaFX构建带有gradle的JAR

翟英达
2023-03-14

我们正在用Adopt JDK11和IntelliJ使用Gradle开发一个JavaFX11应用程序。最后,我们需要一个用于windows的EXE文件(该应用程序仅为windows设计)。在第一次尝试中,我们也使用了gradle中的launch4J,由于以下问题,我们也可以使用BAT文件,我们可以迁移到exe文件。

所以我们的主要目标和问题是,如何才能创建一个可执行的jar文件。

我们进行了几次尝试,结果各不相同,我们完全迷失了方向。

我们为测试目的制作了一个独立的应用程序:

package de.test;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class Main extends Application {

    public static void main(String[] args) {
        launch();
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        VBox vBox = new VBox();

        Button button = new Button("Klick");

        TextField textfield = new TextField();
        TextArea area = new TextArea();
        area.setMinHeight(300);

        button.setOnAction(event -> area.setText(area.getText() + " --  Klick Version 1.0.8"));
        vBox.getChildren().addAll(button, textfield,area);

        primaryStage.setScene(new Scene(vBox));
        primaryStage.setTitle("Test");
        primaryStage.show();
    }
}

肥罐

我们的第一次尝试是使用Gradle的javafx插件创建一个FAT-JAR,无论它有没有modules-info.java文件。这是我们的卷宗

plugins {
    id 'java'
    id 'application'
    id 'org.openjfx.javafxplugin' version '0.0.8'
}

group 'de.test'
version '1.0.8'

sourceCompatibility = 11

javafx {
    modules = ['javafx.controls']
}

mainClassName = 'de.test.Main'

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

repositories {
    mavenLocal()
    mavenCentral()
}

运行gradle clean jar之后,我们尝试使用以下命令java-jar applicationtest-1.0.8.jar执行jar,结果:

compile group: 'org.jboss.resteasy', name: 'resteasy-client', version: '4.3.0.Final'
compile "org.openjfx:javafx-graphics:11.0.2:win"
compile "org.openjfx:javafx-base:11.0.2:win"
compile "org.openjfx:javafx-controls:11.0.2:win"
compile "org.openjfx:javafx-fxml:11.0.2:win"
compile "org.openjfx:javafx-graphics:11.0.2:win"
module ApplicationTest.main {

    requires javafx.controls;

    exports de.test;

}

在调用gradle installDist时,我们使用了以下命令

cd build\install\applicationtest\lib java--add-modules“javafx.controls”--module-path。-jar applicationtest-1.0.8.jar

至少应用程序在此时启动,但布局被以下info消息破坏:

下一种方法是使用jlink和以下模块-info.java

module ApplicationTest.main {
    requires javafx.controls;
    requires javafx.graphics;

    exports de.test;

}

我们需要将gradle文件扩展如下

plugins {
    id 'java'
    id 'application'
    id 'org.openjfx.javafxplugin' version '0.0.8'
    id 'org.beryx.jlink' version '2.10.4'
}

group 'de.test'
version '1.0.8'

sourceCompatibility = 11

mainClassName = 'de.test.Main'

javafx {
    version = 11
    modules = [ 'javafx.controls']
}

jlink {
    options = ['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages']
}


repositories {
    mavenLocal()
    mavenCentral()
}

当使用gradle jlink并执行cd build\image\bin\applicationtest.bat文件时,应用程序从布局开始。

dependencies {
    compile "commons-io:commons-io:2.6"
    compile "org.apache.logging.log4j:log4j-api:2.11.2"
    compile "dom4j:dom4j:1.6.1"
    compile "commons-lang:commons-lang:2.6"
    compile "axis:axis:1.4"
    compile "jaxen:jaxen:1.1.6"
    compile "net.java.dev.jna:platform:3.5.2"
    compile "org.apache.poi:poi:4.1.0"
    compile "org.apache.poi:poi-scratchpad:4.1.0"
    compile "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.4"
}

但是,当我添加其他依赖项时,我会得到不同类型的错误消息。我尝试单独使用每个依赖项来隔离错误消息。

Cannot derive uses clause from service loader invocation in: javax/ws/rs/client/FactoryFinder.find().
Cannot derive uses clause from service loader invocation in: javax/ws/rs/ext/FactoryFinder.find().
Cannot derive uses clause from service loader invocation in: javax/ws/rs/sse/FactoryFinder.find().
Cannot derive uses clause from service loader invocation in: javax/xml/bind/ServiceLoaderUtil.firstByServiceLoader().

ApplicationTest\build\jlinkbase\tmpjars\de.test.merged.module\module-info.java:154: error: the service implementation type must be a subtype of the service interface type, or have a public static no-args method named "provider" returning the service implementation
    provides javax.ws.rs.ext.Providers with org.jboss.resteasy.plugins.interceptors.CacheControlFeature,
                                                                                   ^
ApplicationTest\build\jlinkbase\tmpjars\de.test.merged.module\module-info.java:155: error: the service implementation type must be a subtype of the service interface type, or have a public static no-args method named "provider" returning the service implementation
                org.jboss.resteasy.plugins.interceptors.encoding.ClientContentEncodingAnnotationFeature,
                                                                ^
ApplicationTest\build\jlinkbase\tmpjars\de.test.merged.module\module-info.java:156: error: the service implementation type must be a subtype of the service interface type, or have a public static no-args method named "provider" returning the service implementation
                org.jboss.resteasy.plugins.interceptors.encoding.MessageSanitizerContainerResponseFilter,
                                                                ^
...     
                                            ^
25 errors
package org.apache.logging.log4j.spi is not visible
(package org.apache.logging.log4j.spi is declared in module org.apache.logging.log4j, but module de.test.merged.module does not read it)
package org.apache.logging.log4j.message is not visible
(package org.apache.logging.log4j.message is declared in module org.apache.logging.log4j, but module de.test.merged.module does not read it)
module not found: java.activation
package javax.ws.rs.ext does not exist
package javax.ws.rs.ext does not exist
package javax.ws.rs.ext does not exist

我们现在一事无成。它很可能与modules-info.java有关,但是关于这个主题的说明和文档相当复杂,而且往往非常详细。我们只是想要一个可以在Intellij之外启动的应用程序。

我们对所有解决方案都持开放态度,只要它们奏效。我们不需要一个最先进的解决方案,但我们可以从某种方式获得一个EXE最终(也有一个外部工具的帮助)。我们的应用程序不一定要模块化,但我们既不得到它,也不解决它。

package de.test;

public class Main {
    public static void main(String[] args) {
        MainFX.main(args);
    }

}
package de.test;

import ...;

public class MainFX extends Application {

    public static void main(String[] args) {
        launch();
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
    ...
    }
}

gradle文件如下所示:

plugins {
    id 'java'
    id 'application'
}

group 'de.test'
version '1.0.8'

sourceCompatibility = 11

mainClassName = 'de.test.MainFX'

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

repositories {
    mavenLocal()
    mavenCentral()
}

dependencies {
    compile "commons-io:commons-io:2.6"
    compile "org.apache.logging.log4j:log4j-api:2.11.2"
    compile "dom4j:dom4j:1.6.1"
    compile "commons-lang:commons-lang:2.6"
    compile "axis:axis:1.4"
    compile "jaxen:jaxen:1.1.6"
    compile "net.java.dev.jna:platform:3.5.2"
    compile "org.apache.poi:poi:4.1.0"
    compile "org.apache.poi:poi-scratchpad:4.1.0"
    compile "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.4"

    compile "org.jboss.resteasy:resteasy-multipart-provider:3.7.0.Final"
    compile "org.jboss.resteasy:resteasy-jackson2-provider:3.7.0.Final"
    compile "org.apache.logging.log4j:log4j-core:2.11.2"
    compile "org.jboss.resteasy:resteasy-client:3.7.0.Final"
    compile "org.openjfx:javafx-graphics:11.0.2:win"
    compile "org.openjfx:javafx-base:11.0.2:win"
    compile "org.openjfx:javafx-controls:11.0.2:win"
    compile "org.openjfx:javafx-fxml:11.0.2:win"
    compile "org.openjfx:javafx-graphics:11.0.2:win"
}

结果是非常奇怪的java-jar applicationtest.jar返回

错误:找不到或加载主类DE.Test.MainFx,原因是:java.lang.ClassNotFoundException:DE.Test.MainFx

...
mainClassName = 'de.test.MainFX'

javafx {
    version = 11
    modules = [ 'javafx.controls', 'javafx.fxml', 'javafx.web']
}

jar {
    manifest {
        attributes 'Main-Class': 'de.test.MainLauncher'
    }
    from {
        configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
    }
}
> 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:174)
>         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 de.test.MainLauncher.main(MainLauncher.java:7) 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

因此,我们再次添加了javafx的依赖项,结果如下:

Graphics Device initialization failed for :  d3d, sw
Error initializing QuantumRenderer: no suitable pipeline found
java.lang.RuntimeException: java.lang.RuntimeException: Error initializing QuantumRenderer: no suitable pipeline found
        at com.sun.javafx.tk.quantum.QuantumRenderer.getInstance(QuantumRenderer.java:280)
        at com.sun.javafx.tk.quantum.QuantumToolkit.init(QuantumToolkit.java:222)
        at com.sun.javafx.tk.Toolkit.getToolkit(Toolkit.java:260)
        at com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:267)
        at com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:158)
        at com.sun.javafx.application.LauncherImpl.startToolkit(LauncherImpl.java:658)
        at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:678)
        at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:195)
        at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.RuntimeException: Error initializing QuantumRenderer: no suitable pipeline found
        at com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.init(QuantumRenderer.java:94)
        at com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.java:124)
        ... 1 more
Exception in thread "main" java.lang.RuntimeException: No toolkit found
        at com.sun.javafx.tk.Toolkit.getToolkit(Toolkit.java:272)
        at com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:267)
        at com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:158)
        at com.sun.javafx.application.LauncherImpl.startToolkit(LauncherImpl.java:658)
        at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:678)
        at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:195)
        at java.base/java.lang.Thread.run(Thread.java:834)

共有1个答案

闾丘山
2023-03-14

根据我到目前为止的(痛苦的)经验,让一个大型JavaFX11+项目运行的唯一方法是将所有内容保留在类路径上(也是JavaFX依赖项),并像上一个示例中所做的那样,为主类使用该包装器。(你当前的分级文件是错误的,请看我上面的评论。)试图摆弄模组系统只会让你一无所获,只会浪费你的时间。

我目前正在做以下操作来创建一个exe(或Mac上的应用程序)。

  1. 使用上述常规设置。
  2. 通过Maven/Gradle收集lib文件夹中的所有依赖项。
  3. 使用jlink为程序创建指定的运行时。
  4. 使用jpackage的EA版本创建exe/app。

一旦你想出了你需要的所有选项,这种方法就像一种魅力。

使用jlink构建自己的运行时很简单。

JAVA_HOME=<the java version you want to use>

$JAVA_HOME/bin/jlink --no-header-files --no-man-pages --compress=2 --strip-debug \
--add-modules <a list of the required or just all modules> \
--output java-runtime
 类似资料:
  • 我遵循了https://blog.jetbrains.com/idea/2013/03/packaging-javafx-2-applications-in-intellij-idea-121/中的步骤 但是当我尝试构建工件时,在最后一步中,我得到了这个错误 错误:Java FX Packager:无法生成工件-FX:Deploy在此JDK中不可用 这里有一个快速测试的hello world应用程

  • 我们正在努力将我们的API从Java8升级到Java11。 然而,我们需要同时支持Java8和Java11,因为所有客户端还没有准备好Java11。 如果我们可以使用Java 8和Java 11创建maven build,而不需要复制我们的存储库,也不需要对pom进行任何更改,这是可能的吗。每次为Java 8和Java 11创建构建之前都使用xml?

  • 操作系统:Linux Mint 18.3,Eclipse“2019-06”。使用Gradle 5.4的Gradle包装器。 昨天,我花了大约4个小时试图在Eclipse中组合一个项目,当使用Java11时,这个项目实际上会运行并显示一个JavaFX场景。由于这里的帮助,我最终还是做到了。 但这只是Eclipse中一个沼泽标准的“Java项目”。我实际上需要做的是开发一个Gradle项目,使用Gro

  • 我试图在Windows上用IntelliJ IDEA Ultimate中的JavaFX运行Gradle项目。JavaFX是在我们最新的Git push中添加的,在它开始工作之前。 JDK 11.0.5(来自Oracle站点,不是openJDK),我使用的是Java11,都在IntelliJ中配置 JDK安装目录(特别是/bin目录)添加到我的路径 JDK安装目录中添加的java_home环境变量

  • 我已经添加了版本 注意:我还没有迁移任何测试,所有测试都是JUnit4语法。

  • 如果这很重要,我将使用Gradle4.4和JDK7。