OpenJFX時代のJDK選び - もしくはOpenJFX時代のアプリケーション配布
Java 11からJavaFXがOracle JDKに含まれなくなったことはみなさんご存知の通り。もともとOpenJDKのJDKプロジェクトにはJavaFX (OpenJFX)は含まれていなかったので、Oracle OpenJDKなどにもJavaFXは含まれていません。
でも、ディストリビューションによってはJavaFXを含んでいるものがあります。たとえば、Liberica JDKなどがJavaFXを含んでいます。
なので、JDKソムリエの @yamadamn さんはJavaFXを使うんだったらLiberica JDKを推すのですが、それはハッキリいってまちがいです。
その理由は、デスクトップアプリケーション特有の視点、つまり
アプリケーションを配布しなくてはいけない
ということに対しての配慮がないからです。
これはどういうことかというと、アプリケーションのユーザーにアプリケーションの実行環境を用意してもらわなくてはいけないということです。
はっきりいうと、ユーザーにLeberica JDKをインストールさせるのは、つらすぎるのです。というか、アプリケーションを実行させるために、事前にJDKをインストールさせるというのが無理があると思うのです。
もし、ユーザーのPCにすでに他のJDKがインストールされていたら、それとは別のJDKをインストールさせるのでしょうか?
たとえば、仕事で使うためにAdoptOpenJDK 11がインストールされているとしましょう。ここにJavaFXのアプリケーションを実行させるためだけに、Liberica JDKをインストールさせて、JDKを切り替えさせるなんてことさせるのでしょうか?
どう考えても無理ですよね。
ましてや、ほとんどのユーザーはJDKをインストールしていないのです。アプリケーションを実行させるためにだけ、アプリケーションとは別にJDKをインストールさせるということは、ユーザにとってハードルが高いのです。
Java 8まではJDKといえば、ほぼOracle JDKだけだったので、まだ許されていたかもしれません。しかし、今は複数のOpenJDKディストリビューションが存在しています。GoogleでJDKを検索しても、Liberica JDKはかなり下位にならないと登場しません。そんな誰が作ったかもわからないようなもの (もちろん、Javaアプリの開発者である私たちはLiberica JDKが何かは分かっているはずですが) をユーザにインストールさせるのは酷だと思うわけです。
では、どうすればいいか?
配布するアプリケーションにJREをバンドルさせる
ということです。この観点からJDKを選ぶべきなのです。
JREを同胞させる方法はいくつかありますが、最後に紹介します。
Java 8はやめよう
悪いことはいいません、なるべくJava 11以降のバージョンにしましょう。
OpenJFXではJavaFX 8のバイナリを公開していませんし、ソースのメンテナンスもされていません。たとえば、JavaFX 11以降のバージョンでセキュリティの問題が発見されて、フィックスされたとしても、それがバックポートされることはないのです (ただし、有償のOracle JDK 8だけは、JavaFX 8のサポートを行うようです)。
ということなので、メンテナンスされていないJavaFX 8を使い続けるのはやっぱりよくないと思うわけです。
OpenJFXではJavaFX 11をLTSとして公開しているので、JavaFXはこれを使うのがよいと思います。
とはいうものの、上のリンクからダウンロードして使うことはまずないはずです。Mavenのセントラルレポジトリのものを使えるからです。
追記 JavaFX 11のLTSはGluonの商用サービスのようでした。@aoetk さん、ご指摘ありがとうございます。
現状、JavaFXはバージョンアップしてもバグフィックスやパフォーマンス向上など、大きな機能変更は行われなくなっています。なので、その時の最新のJavaFX (今だったらJavaFX 12.0.1)を使ってしまうのがいいと思います。JavaFX 12.0.1はJava 12用に思えるかもしれませんが、Java 11でも使用することが可能です。
JavaFX 8からJavaFX 11への変更では、ほとんどコードの変更は必要ないはずです。モジュールに対応させるため、一部のAPIのパッケージが変更されたりしていますが、普通にデスクトップアプリを作るときにはほぼ関係ありません。
異なるのはビルドと実行方法です。
JavaFXのアプリケーションで使用するようなライブラリは、ほとんどのものがJavaFX 11に対応しています。たとえば、GUI部品のライブラリであるControlsFXもJavaFX 11に対応しています。
問題はJavaの方で、Java 11に対応していないライブラリも多くあります。でも、デスクトップアプリで使うライブラリはたかが知れているのではないでしょうか。デスクトップアプリと通信するサーバー側はいろいろライブラリ使うかもしれませんけど、そちらはJava 11にする必要はないので。
私が関与したJavaFX 11へのマイグレーションはそれほど多いわけではないのですが、JAXBがJava SEに含まれなくなったことだけを考慮すれば、他のライブラリ(たとえば、Apache Commonsのライブラリとか)はJava 11でも問題なく動作しています。
なぜLiberica JDKはやめるべきなのか
Liberica JDKはユーザーにとってハードルが高すぎる話は前述しましたけど、開発する時にもあまりお勧めできません。
というのも、Liberica JDKはJavaFXが同胞されているため、他のJDKでJavaFXを使った場合とはアプリケーションのビルド/実行方法がまったく違ってしまうからです。
他のJDKを使った場合、JavaFXは単なるライブラリとして扱います。
ほんのちょっとだけ普通のライブラリと違うのが、モジュールアプリケーションではなくてもモジュールの場所を指定するモジュールパス(--module-path)と使用するモジュールの指定(--add-modules)をしなくてはいけないということです。でも、これは普通のライブラリでクラスパスを指定するのと同じようなものです。
しかも、MavenやGradleを使う場合、JavaFXのプラグインがあるので、モジュールパスだのなんだのを気にせずに、まったく普通のライブラリと同じように扱うことができます。
ところが、Liberica JDKではモジュールパスもモジュールの指定も必要ありません。いうなれば、Java 8でのJavaFXの扱いと同じなのですが、もう時代は変わっているのです。
もし、作っているアプリケーションが自分だけで使うのであれば、Liberica JDKでもなんら問題ありません。でも、OSSとしてGitHubなどで公開したいのであれば、他のJDKを使っている人たちでもビルド/実行ができるようにしておかなくてはなりません。
そうすると、結局、Liberica JDKに同胞されているJavaFXではなくて、外部の(たとえば、Mavenのセントラルレポジトリにある) JavaFXを使用する設定にならざるをえません。
では、どのJDKを使えばいいのか?
アプリケーションにJREをバンドルするという前提で考えなくてはなりません。
アプリケーションをフリーで配布するのであれば、有償のサポート付きのJDKを使うことはまずないはずですね。となると、無償のJDKを使うことになります。
繰り返しになりますが、JavaFXは単なるライブラリと割り切った方がよいです。そうすれば、どのJDKを使おうがまったく問題ありません。
だいたいのアプリケーションはMavenもしくはGradleを使って開発されていると思いますが、MavenのセントラルレポジトリにあるJavaFXを使うようにすれば、JDKはどれを使っても同じです。
前述したように、Liberica JDKを使う場合も、バンドルされているJavaFXを使わずに、MavenのセントラルレポジトリのJavaFXを使うようにしましょう。
アプリケーションのリリース間隔が半年未満なのであれば、Oracle OpenJDKでも構わないと思います。新しいバージョンをリリースするときには、新しいJREをバンドルするようにしましょう。
できれば、アプリケーションのバージョンアップ時に、旧バージョンを使っているユーザに通知だせるような仕組みにしておくといいですね。
とはいうものの、ほとんどのアプリケーションはLTSを使いたがるでしょうから、無償でLTSを出しているAdoptOpenJDKやLiberica JDKあたりに落ち着くとは思います。
アプリケーションの配布
アプリケーションを配布する時にはJREをバンドルさせるのがお勧めですが、それにはいくつかの方法があります。
- jlinkを使用してカスタムJREを作成し、そこにアプリケーションのJARやリソース、起動用のバッチ/シェルスクリプトなどを追加する
- 上のパッケージをjpackageを使ってネイティブアプリケーション化する
- Gluon Client Pluginを使ってネイティブアプリケーションを作成する
カスタムJREを作成して、アプリケーションのパッケージを作るのが今のところ一番のお勧めです。
jpackageはJava 8まで存在したjavapackager (もしくはjavafxpackager)をリファインしたものです。現状はまだベータ版で、Java 14がリリースのターゲットになっています。
なので、jpackageを使うのは正式リリース後のJava 14以降がよいと思います。
最後のGluon Client PluginはGraalVMを使ってネイティブイメージを作成するものです。現状、GraalVMはJava 8ベースなのですが、Gluon Client PluginではJava 11もサポートしています。
私もGluon Client Pluginはまだ使っていないので、試してみたら別エントリーで紹介したいと思います。
追記 現状、Gluon Client PluginはMac OS Xだけのサポートでした。LinuxかWindowsをサポートするようになったら、使ってみようと思います。