[OpenJDK11 & JavaFX13] Build a javaFX app with IntelliJ + gradle and create a package that can be distributed with a lightweight JRE

I wanted to create a JavaFX app that can be distributed, but since I made a trial and error, I will summarize it here.

environment

$ cat /etc/os-release 
NAME="Ubuntu"
VERSION="18.04.3 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.3 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic

※macOS Mojave(10.14.6)But I was able to create it by the same procedure.

$ java --version
openjdk version "11.0.4" 2019-07-16
OpenJDK Runtime Environment (build 11.0.4+11-post-Ubuntu-1ubuntu218.04.3)
OpenJDK 64-Bit Server VM (build 11.0.4+11-post-Ubuntu-1ubuntu218.04.3, mixed mode, sharing)

$ jlink --version
11.0.4

JDK selection

At first I was thinking of using a JDK such as Amazon Corretto that ships with JavaFX. However, after reading the following article, I decided to use Openjdk-11 this time, JavaFX as a library, and generate a lightweight JRE at the time of distribution. Selecting a JDK in the OpenJFX era-or distributing applications in the OpenJFX era

procedure

Create a gradle project in IntelliJ

In IntelliJ, create a new gradle project.

Screenshot from 2019-10-01 16-05-10.png

Added settings for javafx to build.gradle

Create build.gradle by referring to the following source described in OpenJFX official website. https://github.com/openjfx/samples/blob/master/IDE/IntelliJ/Modular/Gradle/hellofx/build.gradle

In addition, since "Automatically import this project on changes in build script files" is checked in the IntelliJ settings, the module will be imported.

build.gradle


plugins {
    id 'java'
    id "org.openjfx.javafxplugin" version "0.0.8" //add to
}

group 'com.example'
version '1.0-SNAPSHOT'

sourceCompatibility = 1.8

repositories {
    mavenCentral()
}

dependencies {
    testCompile group: 'junit', name: 'junit', version: '4.12'
}

//add to
javafx {
    version = "13"
    modules = [ 'javafx.controls', 'javafx.fxml' ]
}

//Specify Main class when creating executable Jar
jar {
    manifest {
        attributes 'Main-Class': 'Main'
    }
}

Create a JavaFx class for testing

Main.java


import javafx.application.Application;

public class Main {
    public static void main(String... args){
        Application.launch(MyApplication.class);
    }
}

MyApplication.java


import javafx.application.Application;
import javafx.stage.Stage;

public class MyApplication extends Application {
    public MyApplication(){
        super();
    }

    @Override
    public void start(Stage primaryStage) throws Exception{
        primaryStage.setTitle("Hello");
        primaryStage.setWidth(300);
        primaryStage.setHeight(200);
        primaryStage.show();
    }
}

As a result of executing this, the following screen will appear. Screenshot from 2019-10-01 16-43-52.png

build to create an executable JAR file

At the console, run gradle build. If there is no problem, I think that an executable jar file will be created. Screenshot from 2019-10-01 16-47-08.png

If you try to execute the jar file in this state ... Screenshot from 2019-10-01 16-48-17.png

As you can see, I get angry that the javafx.application.Application class is missing. This is because there is no JavaFX module in jre of openjdk-11.0.4.

Create a lightweight JRE

Now let's use jlink to create a lightweight jre to make this jar file work! This time, I referred to the following article. How to make a lightweight JRE for distribution

First, download jmods from Downloads on the following page. https://openjfx.io/ Screenshot from 2019-10-01 16-54-31.png

Extract the downloaded zip file and place it in an appropriate path. (This time, it is placed in / usr / lib / jvm / javafx-13-openjfx / javafx-jmods-13.)

This time, I downloaded jmods for Linux.

Next, use the ``` jdeps $ {jar file path}` `` command to check the modules required to execute this jar file. Screenshot from 2019-10-01 16-56-53.png

This time, it seems good to use the following modules. · Java.lang-> java-base · Java.application-> javafx.base -Javafx.stage-> javafx.controls

Now that we know the modules we need, let's create a lightweight jre. I was able to create it by specifying the above module with the following jlink command.

$ jlink --compress=2 --module-path /usr/lib/jvm/java-11-openjdk-amd64/jmods:/usr/lib/jvm/javafx-13-openjfx/javafx-jmods-13 --add-modules java.base,javafx.base,javafx.controls --output jre

A jre directory has been created in the current path. jre/bin/javaBinaries have also been created.

Screenshot from 2019-10-01 17-23-21.png

Execute the JAR file using the created JRE.

Now, let's execute the program using the jre created last.

$ ./jre/bin/java -jar build/libs/javafx-sample-1.0-SNAPSHOT.jar 

Screenshot from 2019-10-01 17-30-28.png

I was able to execute it safely!

After that, put the JAR file and jre in a directory, create a shell or bat file for execution, or put them in an app package, and you're done. (The following is an example of creating a shell by putting it in a folder)

$ ls
javafx-sample-1.0-SNAPSHOT.jar  jre  start.sh

$ cat start.sh
#!/bin/sh
BASE=$(cd $(dirname $0); pwd)
$BASE/jre/bin/java -jar $BASE/javafx-sample-1.0-SNAPSHOT.jar

## sh start.Can be executed with sh

Thank you for your hard work!

For the first time, I created a lightweight JRE using commands such as jlink and jdeps, but I think this method is easy when creating a JavaFX application that can be executed independently of the user's environment (jdk, etc.). The size of the jre directory this time is 368.3MB, so I wonder if it will be heavier if I can do more.

that's all. Thank you very much!

Recommended Posts

[OpenJDK11 & JavaFX13] Build a javaFX app with IntelliJ + gradle and create a package that can be distributed with a lightweight JRE
Create a page control that can be used with RecyclerView
Create a jar file that can be executed in Gradle
Performance analysis and failure diagnostic tools that can be used with OpenJDK
Create a JVM for app distribution with JDK9 modules and jlink
Create a flyway jar with maven and docker build (migrate) with docker-maven-plugin
Build a Java project with Gradle
Simple slot machine implementation that can be used with copy and paste
[Rails] "pry-rails" that can be used when saving with the create method
How to create a server executable JAR and WAR with Spring gradle