web-dev-qa-db-fra.com

JavaFX 11: Créer un fichier jar avec Gradle

J'essaie de mettre à niveau un projet JavaFX de la version 8 Java) vers la version 11. Cela fonctionne lorsque j'utilise la tâche "exécuter" Gradle ( j'ai suivi le tutoriel Openjfx =), mais lorsque je crée (avec la tâche "jar" Gradle) et exécute (avec "Java -jar") un fichier jar, le message "Erreur: des composants d'exécution JavaFX sont manquants et sont nécessaires pour exécuter cette application" s'affiche. .

Voici mon fichier 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'
        ]
    }
}

Savez-vous ce que je devrais faire?

24
Flpe

Si quelqu'un est intéressé, j'ai trouvé un moyen de créer des fichiers jar pour un projet JavaFX11 (avec Java 9)). Je ne l'ai testé que sous Windows (si l'application est également pour Linux, je pense nous devons suivre les mêmes étapes mais sous Linux pour obtenir les fichiers jar JavaFX pour Linux).

J'ai un module "Project.main" (créé par IDEA, lorsque j'ai créé un projet Gradle):

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

Le fichier module-info.Java:

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

Le fichier 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
}

Le fichier settings.gradle:

rootProject.name = 'Project'

Et les commandes 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

Avec Java/JavaFX 11, le jar shadow/fat ne fonctionnera pas.

Comme vous pouvez le lire ici :

Cette erreur provient de Sun.launcher.LauncherHelper dans le module Java.base. La raison en est que l'application principale étend Application et possède une méthode principale. Si tel est le cas, le LauncherHelper vérifiera si le module javafx.graphics est présent en tant que module nommé:

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

Si ce module n'est pas présent, le lancement est annulé. Par conséquent, l'utilisation des bibliothèques JavaFX en tant que fichiers JAR sur le chemin d'accès aux classes n'est pas autorisée dans ce cas.

De plus, chaque jar JavaFX 11 a un module-info.class fichier, au niveau de la racine.

Lorsque vous regroupez tout le contenu des fichiers jar dans un seul et même fichier java, qu'advient-il des fichiers portant le même nom et le même emplacement? Même si le pot de graisse les conserve tous, comment s’identifie-t-il en tant que module unique?

Il y a une demande pour supporter ceci, mais elle n'a pas encore été traitée: http://openjdk.Java.net/projects/jigsaw/spec/issues/#MultiModuleExecutableJARs

Fournissez un moyen de créer un "uber-JAR" modulaire exécutable contenant plusieurs modules, en préservant les identités et les limites des modules, afin qu'une application entière puisse être livrée sous la forme d'un artefact unique.

Le plugin shadow a toujours du sens pour regrouper toutes vos dépendances autres dans un seul fichier jar, mais vous devrez tout de même exécuter quelque chose du genre:

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

Cela signifie qu'après tout, vous devrez installer le SDK JavaFX (par plate-forme) pour exécuter ce fichier jar qui utilisait des dépendances JavaFX de maven central.

Vous pouvez également utiliser jlink pour créer un JRE léger, mais votre application doit être modulaire.

Vous pouvez également utiliser Javapackager pour générer un programme d’installation pour chaque plate-forme. Voir http://openjdk.Java.net/jeps/34 qui produira un conditionneur pour Java 12.

Enfin, il existe une version expérimentale de Javapackager fonctionnant avec Java 11/JavaFX 11: http://mail.openjdk.Java.net/pipermail/openjfx-dev/ 2018-septembre/022500.html

[~ # ~] éditer [~ # ~]

Depuis le Java launcher vérifie si la classe principale s’étend javafx.application.Application, et dans ce cas, le runtime JavaFX est disponible en tant que modules (et non en tant que fichiers JAR). Une solution possible pour le faire fonctionner consiste à ajouter une classe nouvelle Main qui sera la classe principale. classe de votre projet, et cette classe sera celle qui appelle votre classe d’application JavaFX.

Si tu as un javafx11 package avec la classe Application:

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);
    }

}

Ensuite, vous devez ajouter cette classe à ce paquet:

public class Main {

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

Et dans votre fichier de construction:

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

Maintenant vous pouvez lancer:

./gradlew run

ou

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

JavaFX from FAT jar

L’objectif final est d’avoir les modules JavaFX en tant que modules nommés sur le chemin du module, ce qui ressemble à une solution de contournement rapide/moche pour tester votre application. Pour la distribution, je suggère toujours les solutions mentionnées ci-dessus.

26
José Pereda