gradle jar java-11 javafx-11

JavaFX 11: Crea un archivo jar con Gradle



java-11 javafx-11 (2)

Estoy intentando actualizar un proyecto JavaFX de la versión 8 de Java a la versión 11. Funciona cuando uso la tarea Gradle "ejecutar" ( seguí el tutorial de Openjfx ), pero cuando compilo (con la tarea Gradle "jar") y ejecuto (con "java -jar") un archivo jar, aparece el mensaje "Error : Faltan componentes de tiempo de ejecución de JavaFX y son necesarios para ejecutar esta aplicación "aparece.

Aquí está mi archivo 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'' ] } }

¿Sabes lo que debo hacer?


Con Java / JavaFX 11, el jarro de sombra / grasa no funcionará.

Como puedes leer here :

Este error proviene de sun.launcher.LauncherHelper en el módulo java.base. La razón de esto es que la aplicación principal extiende la Application y tiene un método principal. Si ese es el caso, el LauncherHelper comprobará que el módulo javafx.graphics esté presente como un módulo con nombre:

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

Si ese módulo no está presente, el lanzamiento se cancela. Por lo tanto, tener las bibliotecas de JavaFX como jars en la ruta de clase no está permitido en este caso.

Lo que es más, todos los archivos JavaFX 11 tienen un archivo module-info.class , en el nivel raíz.

Cuando agrupa todo el contenido de los frascos en un solo frasco, ¿qué sucede con los archivos con el mismo nombre y la misma ubicación? Incluso si la jarra de grasa los guarda a todos, ¿cómo se identifica eso como un solo módulo?

Hay una solicitud para admitir esto, pero aún no se ha solucionado: http://openjdk.java.net/projects/jigsaw/spec/issues/#MultiModuleExecutableJARs

Proporcione un medio para crear un ejecutable "uber-JAR" que contenga más de un módulo, preservando las identidades y los límites de los módulos, de modo que toda la aplicación se pueda enviar como un solo artefacto.

El complemento de la sombra todavía tiene sentido agrupar todas tus otras dependencias en un solo archivo, pero después de todo tendrás que ejecutar algo como:

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

Esto significa que, después de todo, tendrá que instalar el SDK de JavaFX (por plataforma) para ejecutar ese archivo jar que usaba las dependencias de JavaFX de Maven Central.

Como alternativa, puede intentar usar jlink para crear un JRE ligero, pero su aplicación debe ser modular.

También puedes usar el Javapackager para generar un instalador para cada plataforma. Consulte http://openjdk.java.net/jeps/343 que producirá un empaquetador para Java 12.

Finalmente, hay una versión experimental de Javapackager que funciona con Java 11 / JavaFX 11: http://mail.openjdk.java.net/pipermail/openjfx-dev/2018-September/022500.html

EDITAR

Dado que el javafx.application.Application Java comprueba si la clase principal extiende javafx.application.Application , y en ese caso requiere que el tiempo de ejecución de JavaFX esté disponible como módulos (no como jars), una posible solución para hacerlo funcionar, debería agregar una nueva clase principal que será la clase principal de su proyecto, y esa clase será la que llame a su clase de aplicación JavaFX.

Si tiene un paquete javafx11 con la clase de aplicación:

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

Luego tienes que agregar esta clase a ese paquete:

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

Y en tu archivo de compilación:

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

Ahora puedes correr:

./gradlew run

o

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

El objetivo final es tener los módulos JavaFX como módulos con nombre en la ruta del módulo, y esto parece una solución rápida / fea para probar su aplicación. Para su distribución aún sugeriría las soluciones mencionadas anteriormente.


Si alguien está interesado, encontré una manera de crear archivos jar para un proyecto JavaFX11 (con módulos Java 9). Lo probé solo en Windows (si la aplicación también es para Linux, creo que tenemos que hacer los mismos pasos pero en Linux para obtener los jars de JavaFX para Linux).

Tengo un módulo "Project.main" (creado por IDEA, cuando creé un proyecto de Gradle):

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

El archivo module-info.java:

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

El archivo 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 }

El archivo settings.gradle:

rootProject.name = ''Project''

Y los comandos de 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"