web-dev-qa-db-ja.com

JavaFX 11:Gradleを使用してjarファイルを作成する

JavaFXプロジェクトを8 Javaバージョンから11バージョンにアップグレードしようとしています。 「run」Gradleタスクを使用すると機能します( Openjfxチュートリアルに従いました )が、ビルド(「jar」Gradleタスクを使用)および実行(「Java -jar」を使用)するとjarファイルには、「エラー:JavaFXランタイムコンポーネントがありません。このアプリケーションを実行するために必要です」というメッセージが表示されます。

これが私のbuild.gradleファイルです:

group 'Project'
version '1.0'
apply plugin: 'Java'
sourceCompatibility = 1.11

repositories {
    mavenCentral()
}

def currentOS = org.gradle.internal.os.OperatingSystem.current()
def platform
if (currentOS.isWindows()) {
    platform = 'win'
} else if (currentOS.isLinux()) {
    platform = 'linux'
} else if (currentOS.isMacOsX()) {
    platform = 'mac'
}
dependencies {
    compile "org.openjfx:javafx-base:11:${platform}"
    compile "org.openjfx:javafx-graphics:11:${platform}"
    compile "org.openjfx:javafx-controls:11:${platform}"
    compile "org.openjfx:javafx-fxml:11:${platform}"
}

task run(type: JavaExec) {
    classpath sourceSets.main.runtimeClasspath
    main = "project.Main"
}

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

compileJava {
    doFirst {
        options.compilerArgs = [
                '--module-path', classpath.asPath,
                '--add-modules', 'javafx.controls,javafx.fxml'
        ]
    }
}

run {
    doFirst {
        jvmArgs = [
                '--module-path', classpath.asPath,
                '--add-modules', 'javafx.controls,javafx.fxml'
        ]
    }
}

私が何をすべきか知っていますか?

24
Flpe

誰かが興味があるなら、JavaFX11プロジェクト用のjarファイルを作成する方法を見つけました(Java 9モジュール)。 Windowsでのみテストしました(アプリケーションがLinuxにも対応している場合、LinuxでJavaFX jarを取得するにはLinuxでも同じ手順を実行する必要があると思います)。

「Project.main」モジュール(Gradleプロジェクトを作成したときにIDEAで作成)があります。

 src
 +-- main
 |   +-- Java
     |   +-- main
         |   +-- Main.Java (from the "main" package, extends Application)
     |   +-- module-info.Java
 build.gradle
 settings.gradle
 ...

Module-info.Javaファイル:

module Project.main {
    requires javafx.controls;
    exports main;
}

Build.gradleファイル:

plugins {
    id 'Java'
}

group 'Project'
version '1.0'
ext.moduleName = 'Project.main'
sourceCompatibility = 1.11

repositories {
    mavenCentral()
}

def currentOS = org.gradle.internal.os.OperatingSystem.current()
def platform
if (currentOS.isWindows()) {
    platform = 'win'
} else if (currentOS.isLinux()) {
    platform = 'linux'
} else if (currentOS.isMacOsX()) {
    platform = 'mac'
}
dependencies {
    compile "org.openjfx:javafx-base:11:${platform}"
    compile "org.openjfx:javafx-graphics:11:${platform}"
    compile "org.openjfx:javafx-controls:11:${platform}"
}

task run(type: JavaExec) {
    classpath sourceSets.main.runtimeClasspath
    main = "main.Main"
}

jar {
    inputs.property("moduleName", moduleName)
    manifest {
        attributes('Automatic-Module-Name': moduleName)
    }
}

compileJava {
    inputs.property("moduleName", moduleName)
    doFirst {
        options.compilerArgs = [
                '--module-path', classpath.asPath,
                '--add-modules', 'javafx.controls'
        ]
        classpath = files()
    }
}

task createJar(type: Copy) {
    dependsOn 'jar'
    into "$buildDir/libs"
    from configurations.runtime
}

Settings.gradleファイル:

rootProject.name = 'Project'

そしてGradleコマンド:

#Run the main class
gradle run

#Create the jars files (including the JavaFX jars) in the "build/libs" folder
gradle createJar

#Run the jar file
cd build/libs
Java --module-path "." --module "Project.main/main.Main"
3
Flpe

Java/JavaFX 11では、shadow/fat jarは機能しません。

あなたが読むことができるように ここ

このエラーは、Java.baseモジュールのSun.launcher.LauncherHelperから発生します。これは、メインアプリがApplicationを拡張し、mainメソッドを持っているためです。その場合、LauncherHelperは、名前付きモジュールとして存在するjavafx.graphicsモジュールをチェックします。

Optional<Module> om = ModuleLayer.boot().findModule(JAVAFX_GRAPHICS_MODULE_NAME);

そのモジュールが存在しない場合、起動は中止されます。したがって、この場合、クラスパス上のJavaFXライブラリをjarとして使用することはできません。

さらに、すべてのJavaFX 11 jarには、ルートレベルにmodule-info.classファイルがあります。

すべてのjarコンテンツを1つのファットjarにバンドルすると、同じ名前と同じ場所のファイルはどうなりますか?ファットjarがそれらすべてを保持している場合でも、それは単一のモジュールとしてどのように識別されますか?

これをサポートする要求がありますが、まだ対処されていません: http://openjdk.Java.net/projects/jigsaw/spec/issues/#MultiModuleExecutableJARs

複数のモジュールを含む実行可能なモジュール式「uber-JAR」を作成し、モジュールの識別と境界を保持する手段を提供して、アプリケーション全体を単一のアーティファクトとして出荷できるようにします。

シャドウプラグインは、すべてのother依存関係を1つのjarにバンドルするのに意味がありますが、やはり次のようなものを実行する必要があります。

Java --module-path <path-to>/javafx-sdk-11/lib \
   --add modules=javafx.controls -jar my-project-ALL-1.0-SNAPSHOT.jar

これは、結局のところ、JavaFX SDKを(プラットフォームごとに)インストールして、Maven CentralからJavaFX依存関係を使用していたjarを実行する必要があることを意味します。

別の方法として、jlinkを使用して軽量JREを作成することもできますが、アプリはモジュール式である必要があります。

また、Javapackagerを使用して、プラットフォームごとにインストーラーを生成できます。 http://openjdk.Java.net/jeps/34 を参照してください。これにより、Java 12のパッケージャーが生成されます。

最後に、Java 11/JavaFX 11で動作するJavapackagerの実験バージョンがあります。 http://mail.openjdk.Java.net/pipermail/openjfx-dev/2018-September /022500.html

編集

Javaランチャーはメインクラスがjavafx.application.Applicationを拡張するかどうかをチェックするため、その場合はJavaFXランタイムをモジュールとして(jarとしてではなく)使用できる必要があるため、動作させるための可能な回避策は次のとおりです。プロジェクトのメインクラスになるnewメインクラスを追加し、そのクラスがJavaFXアプリケーションクラスを呼び出すクラスになります。

Applicationクラスを持つjavafx11パッケージがある場合:

public class HelloFX extends Application {

    @Override
    public void start(Stage stage) {
        String javaVersion = System.getProperty("Java.version");
        String javafxVersion = System.getProperty("javafx.version");   
        Label l = new Label("Hello, JavaFX " + javafxVersion + ", running on Java " + javaVersion + ".");
        Scene scene = new Scene(new StackPane(l), 400, 300);
        stage.setScene(scene);
        stage.show();
    }

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

}

次に、このクラスをそのパッケージに追加する必要があります。

public class Main {

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

そして、ビルドファイルで:

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

これで実行できます:

./gradlew run

または

./gradlew jar
Java -jar build/libs/javafx11-1.0-SNAPSHOT.jar

JavaFX from FAT jar

最終的な目標は、モジュールパス上で名前付きモジュールとしてJavaFXモジュールを使用することです。これは、アプリケーションをテストするための迅速/ ugい回避策のように見えます。配布については、上記のソリューションを引き続き提案します。

26
José Pereda