torutkのブログ

ソフトウェア・エンジニアのブログ

JavaFXアプリケーションのJDK 11対応(配布編)

はじめに

JDK 8でのJavaFXアプリケーションは、javapackagerコマンドを使ってアプリケーションとアプリケーションの実行に必要なJava実行環境をまとめて固めて配布することができました。固め方には、zipアーカイブの他、WindowsLinuxMacOSそれぞれのソフトウェアパッケージ形式(インストーラー)とすることも可能です。

しかし、JDK 11からはJavaFXが分離した際にjavapackagerコマンドも外されてしまいました。OpenJDKでは、javapackagerを代替する新しい機能を開発中*1ですが、早くてJDK 12からとなります。それまでの間、jlinkコマンドを使ってアプリケーションとアプリケーションの実行に必要なJava実行環境をまとめることとします。なお、jlinkはOS固有のパッケージ形式(インストーラー)を作成することはできません。

jlinkコマンドを使った実行イメージの作成

jlinkコマンドは、指定したモジュールが依存するモジュール群をJDKから抜きだして、実行イメージまとめるのに使います。

モジュール対応したJavaFXアプリケーションの実行イメージの作成

JavaFXアプリケーションが、モジュール対応している場合はjlinkコマンドで簡単に実行イメージを作成することができます。

ただし、モジュールパスでJavaFXライブラリのパスを指定するときは、JavaFX SDKを展開したディレクトリではなく、JavaFX jmodsを展開したディレクトリを指定します。

D:\work\EarthGadget> jlink --module-path "C:\Program Files\Java\JavaFX\javafx-jmods-11.0.1";dist ^
--add-modules com.torutk.gadget.earth ^
--output runtime ^
--launcher earthgadget=com.torutk.gadget.earth/com.torutk.gadget.earth.EarthGadgetApp
  • --module-pathでは、JDK標準以外のモジュールを収容するディレクトリを指定します。ここでは、JavaFX jmodsファイルのあるディレクトリ(C:\Program Files\Java\JavaFX\javafx-jmods-11.0.1)と、アプリケーションのモジュール化JARファイルのあるディレクトリ(カレントディレクトリ下のdist)を指定しています。
  • --add-modulesでは、アプリケーションのメインモジュール(com.torutk.gadget.earth)を指定しています。
  • --outputでは、実行イメージを生成するディレクトリを指定しています。
  • --launcherでは、実行イメージの中にアプリケーション起動用のコマンド(シェルスクリプト/バッチファイル)の名前と起動するモジュールおよびメインクラス名を指定しています。

実行イメージが展開されるディレクトリに、JavaFX関係のライブラリ(ネイティブライブラリのdllファイル、クラスライブラリのJARファイル等)も展開されます。

outputオプションで指定したruntimeディレクトリ下のbinディレクトリには、launcherオプションで指定した起動スクリプトファイル(earthgadget)/起動バッチファイル(earthgadget.bat)があるので、UNIX系OSなら前者を、Windows OSなら後者を実行するとJavaFXアプリケーションが立ち上がります。

jlinkコマンドのmodule-pathオプションで、JavaFXSDKのlibディレクトリを指定すると、実行イメージの中にネイティブライブラリが含まれないので実行時にエラーとなってしまいます。jlinkコマンドでJavaFXを指定する場合は、JavaFXのjmodsを指定します。

モジュール対応していないJavaFXアプリケーションの実行イメージ作成(改訂)

JavaFXアプリケーションがモジュール対応していない場合は、JavaFXアプリケーションが必要とするモジュールをjdepsコマンドでリストアップしてからjlinkコマンドでリストアップされたモジュールをそれぞれ指定します。

ただし現時点ではJDKのモジュールから必要なものを抜粋した実行イメージを生成することができますが、実行イメージにJavaFXライブラリとアプリケーションを含めることはできませんでした。

jdepsでアプリケーションの実行に必要なモジュールを調べる

まず、アプリケーションJARファイル(非モジュール対応)をjdepsで解析します。

ここで、非モジュールJARの依存関係を解析する場合、jdepsコマンドのオプション--print-module-depsおよび--list-depsは使用しないのがミソです(id:skrbさんの次のブログ参照)。

skrb.hatenablog.com

まずは、アプリケーションJARファイルだけを指定した場合の実行例です。

D:\work\EarthGadget> jdeps -s dist\EarthGadget.jar
EarthGadget.jar -> java.base
EarthGadget.jar -> java.prefs
EarthGadget.jar -> 見つかりません

D:\work\EarthGadget>

アプリケーションJARが依存するJDKのモジュールのみ表示されます。JavaFXのモジュールはリストされません。また、JavaFXライブラリが必要とするJDKのモジュールもリストされていません。

そこで、JavaFXライブラリを解析対象に追加します。

D:\work\EarthGadget> jdeps -s --module-path "C:\Program Files\Java\JavaFX\javafx-sdk-11.0.1\lib" dist\EarthGadget.jar
EarthGadget.jar -> java.base
EarthGadget.jar -> java.prefs
EarthGadget.jar -> javafx.base
EarthGadget.jar -> javafx.controls
EarthGadget.jar -> javafx.graphics
EarthGadget.jar -> 見つかりません
javafx.base -> java.base
javafx.base -> java.desktop
javafx.controls -> java.base
javafx.controls -> javafx.base
javafx.controls -> javafx.graphics
javafx.fxml -> java.base
javafx.fxml -> java.scripting
javafx.fxml -> java.xml
javafx.fxml -> javafx.base
javafx.fxml -> javafx.graphics
javafx.graphics -> java.base
javafx.graphics -> java.desktop
javafx.graphics -> java.xml
javafx.graphics -> javafx.base
javafx.graphics -> jdk.unsupported
javafx.media -> JDK removed internal API
javafx.media -> java.base
javafx.media -> javafx.base
javafx.media -> javafx.graphics
javafx.swing -> java.base
javafx.swing -> java.datatransfer
javafx.swing -> java.desktop
javafx.swing -> javafx.base
javafx.swing -> javafx.graphics
javafx.swing -> jdk.unsupported.desktop
javafx.swt -> java.base
javafx.swt -> javafx.base
javafx.swt -> javafx.graphics
javafx.swt -> 見つかりません
javafx.web -> java.base
javafx.web -> java.desktop
javafx.web -> java.xml
javafx.web -> javafx.base
javafx.web -> javafx.controls
javafx.web -> javafx.graphics
javafx.web -> javafx.media
javafx.web -> jdk.jsobject
javafx.web -> jdk.xml.dom

なお、--module-pathに、JavaFXSDKではなく、JMODの方を指定すると何故か依存が解析されませんでした。

D:\work\EarthGadget> jdeps -s --module-path "C:\Program Files\Java\javafx\javafx-jmods-11.0.1" dist\EarthGadget.jar
EarthGadget.jar -> java.base
EarthGadget.jar -> java.prefs
EarthGadget.jar -> 見つかりません

D:\work\EarthGadget> 

非モジュール対応アプリケーションJARファイル(EarthGadget.jar)が依存しているのは

となります。よって、jlink でこれらを指定すればあとは依存関係を辿って必要なモジュールが取り込まれた実行イメージが生成されます。なお、java.baseは暗黙で使用されるモジュールなので指定を省略できます。javafx.graphicsはjavafx.controlsが依存しているのでこちらも省略できます。javafx.baseはjavafx.controlsが依存しているのでこちらも省略できます。

jlinkで非モジュール対応アプリケーションJARのための実行イメージを生成する
D:\work\EarthGadget> jlink --add-modules javafx.controls,java.prefs ^
 --module-path "C:\Program Files\Java\JavaFX\javafx-jmods-11.0.1" ^
 --output runtime

生成された runtime ディレクトリの容量は約87MBとなりました。
JavaFXライブラリ(クラスライブラリおよびネイティブライブラリ)も含まれています。
なお、アプリケーションはこのruntimeには含まれません。

jlinkで作成した実行イメージを使ってアプリケーションを実行する
D:\work\EarthGadget> runtime\bin\java -jar dist\EarthGadget.jar

まとめ

  • モジュール対応したJavaFXアプリケーションは、jlinkコマンドで実行に必要なJDK、ライブラリ(Javaクラスライブラリ、ネイティブライブラリ)、アプリケーションをまとめたアプリケーション実行イメージを生成できる。
  • モジュールに対応していないJavaFXアプリケーションは、jdepsコマンドで実行に必要なJDKのモジュールを解析し、続いてjlinkコマンドで必要なモジュールを抜粋し実行イメージを生成する。ただし、非モジュール対応のJARファイルは実行イメージには取り込まれない。

*1:JEP 343: Packaging Tool