ひらおかゆみのなげやりブログ

もう、なげやりです…

Java 8で作成したJavaFXアプリケーションをJava 9で動かす

このエントリは、JavaFX Advent Calendar 2017 の 4 日目です。昨日は @boochnich さんの「JavaFXとHiDPI」、明日は今のところ未定です。

昨年はわたしの誕生日枠で JavaFX の 3D 機能を使って小惑星のビューワを作成しました。

 

blog.yumix.net

 

今回はこのビューワをJava 9に対応させる方法について調べてみました。

方法1: Java 8 で作成したアプリケーションをそのまま動かす

javacの -source と -target がともに 1.8 (または 8) の場合、特に変更することはありません。互換性は維持されていますのでご安心を。JDK 9の新機能を利用できないデメリットはありますが、とりあえず何もしなくても動作するのはお手軽です。なお、JDK 8は -source / -target に 1.8 と 8 のどちらかでも指定できるようになっていますが、JDK 9 では 1.9 は指定できず 9 のみ使用できます。

方法2: Java 9 のモジュール機能を使用してプロジェクトを修正する

本来はこちらの方法が推奨なのでしょう。まずは、ソースファイルのレイアウトからご覧ください。

f:id:yumix_h:20171203025621p:plain

Java 8 までとの相違点は以下の通りです。

  • src ディレクトリ以下にパッケージをまとめるディレクトリ(この例ではasteroid)を作成する。Eclipseではパッケージ扱いされるのでなんかキモい。
  • 上記のフォルダにJavaのソースファイル等とmodule-info.javaファイルを格納する。

Eclipse Oxygen 1a組み込みのMavenはバージョンが古いのか、挙動不審な点が多々見られました。最新版のMavenをセットアップして、そちらを使うように設定したほうがよさそうです。

訂正:Eclipse 4.7.1aでは、Maven形式のプロジェクトではJava 9のJigsawは使えないようです。EclipseのJavaプロジェクトで作成して正常に動いたプログラムをMaven形式に変換した途端にjava.lang.module.FindExceptionで動作しなくなったので、原因はMavenにあるとみて間違いなさそうです。MavenというツールそのものがJava 9のJigsawに対応できていないのか、それともEclipseのMaven周りの問題なのかは、今のところ不明です。

さて、問題なのは module-info.java をどう書けばよいかです。Jigsawのメリットとして使わないモジュールを除外できるというのがあります(特にjavapackagerでネイティブ版を作成したときは効果大です)。でも、JDK 9のドキュメントにはモジュール間の依存関係は書いてあるのですが、JDK 8までのように「とりあえず全部」が難しくなっています。

JDK 9では何もしないとjava.baseというモジュールが使えます。残念ながらその中にJavaFXのモジュールは含まれていません。そこで、module-info.javaにJavaFXのモジュールを取り込むように設定する必要があります(そのため、JDK 9ではファイルのレイアウトが変わります)。

JavaFXのモジュール依存関係を見てみると、javafx.baseを起点としていくつかのスーパーセットが定義されています。そして一番広範囲に API をカバーしているモジュールは、javafx.fxml、javafx.media、javafx.web、javafx.swingの4種類です。つまりこの4モジュールを取り込めば、JDK 8とほぼ同じ範囲の API が使えるようになります。

とりあえず動けばいいや、と思う方は以下のように module-info.java を記述すればたぶん大丈夫です。

module asteroid {
    requires javafx.web;
requires javafx.fxml;
requires javafx.media;
requires javafx.swing;

モジュール名は、モジュールをまとめるディレクトリ名(今回の例ではasteroid)と一致するようにすればOK。 

モジュールについて感覚がつかめてきたら、取り込むモジュールをもっと範囲の狭いもの(javafx.controlsなど)に絞り、使わないものは除外すると、特にjavapackagerでJDKと一緒にパッケージしたときサイズが小さくなります。

結論: Eclipseの場合、普通のJavaプロジェクト(Maven形式でない)に限り、Java 9で動作させることができるようです。