JDK 9 EA上でNetBeans IDE 開発版を動かす(動いた)
id:torutk:20160722で、JDK 9 EA上でNetBeans IDE開発版はまだ動いていないと書いてから1年近くが過ぎました。もうすぐJDK 9もリリース(今年9月予定)ということもあり、そろそろ動く頃かと確認してみました。
動作環境
OS:Windows 10 1607 64bit
JDK: Java SE 9 Development Kit, Early Access b174 64bit
NetBeans IDE: NetBeans IDE dev 201706160001
インストール
最初にJDK 9を入れておきます。
NetBeans IDE devをインストールするときに、使用するJDKの選択でJDK 9が指定できるようになります。
前のバージョンの設定を引き継ぐとトラブルの元なので、前のバージョンの設定を引き継ぐかインストーラーから聞かれたら引き継がないを指定します。
トラブルメモ
インストール後、起動すると多数のモジュールが見つからないといったエラーが表示されるマシンがありました。同じバージョンを入れた別のマシンでは動いていたので、一度アンインストールし、ユーザーの作業フォルダ・キャッシュフォルダを削除して、再度インストールたところ起動するようになりました。
プラグインのインストール
プラグインポータルで公開されているプラグインは、開発版ではデフォルトで配布サイトが設定されていないので、NetBeans IDE 8.2のプラグインポータルサイトを設定します。
http://plugins.netbeans.org/nbpluginportal/updates/8.2/catalog.xml.gz
次の2つをインストールしました。
なお、Darcula LAF foor NetBeansを入れると、NetBeans起動時にエラーダイアログが表示されますが、[取消]ボタンを押して続行することができます。
Jigsaw(モジュール)の確認
Java SE 9 では、(仕様の承認が遅れていますが)モジュール仕様(開発コード:Jigsaw)が導入されます。そこで、モジュール仕様の確認をしてみます。
まず、新規プロジェクトで、JavaFX FXMLアプリケーション を選択してJavaFXアプリケーションの雛形を生成します。
とりあえず、実行して、問題なくビルド&実行できることを確認します。
次に、新規ファイルで、Java Module Info を選択します。
選択直後のプロジェクトビューとmodule-info.javaのコードは次の画面になります。
module-info.javaを追加すると、依存関係を定義していないモジュールのクラスを使用しているソースファイルがエラーとして表示されます。
エラー行にカーソルを持っていくと、次のようにエラー内容が表示されます。
エラーに従って、必要なモジュールをmodule-info.javaに記述していきます。
キーワード(requiresやexports)が識別され、モジュール名も補完候補が表示され、楽に入力できるようになっています。
module-info.javaに、javafx.grahicsモジュールを記述すると、次のようにエラーが解消されます。
- module-info.javaを保存する必要があります。
同様に、module-info.javaに、javafx.fxmlモジュール、javafx.controlsモジュールを記述していきます。
module com.torutk.hello { exports com.torutk.hello; requires javafx.controls; requires javafx.fxml; requires javafx.graphics; }
ビルドしたJARファイルを、コマンドラインからモジュール指定して実行してみます。
HelloJavaFx>java --module-path dist -m com.torutk.hello/com.torutk.hello.HelloApp Exception in Application start method java.lang.reflect.InvocationTargetException at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) : Caused by: javafx.fxml.LoadException: file:///D:/work/java/NetBeansProjects/jigsaw/HelloJavaFx/dist/HelloJavaFx.jar!/com/torutk/hello/HelloView.fxml:11 at javafx.fxml/javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2625) : Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make field private javafx.scene.control.Label com.torutk.hello.HelloViewController.label accessible: module com.torutk.hello does not "opens com.torutk.hello" to module javafx.fxml at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:337) :
実行できましたが、実行時例外が発生してしまいました。
FXMLLoader.load からの呼び出して、privateフィールドへのアクセスが拒否されたためのようです。
javafx.fxmlモジュールから、com.torutk.helloモジュールのprivate要素にリフレクションでアクセスするには、追加設定が必要なようです。
ざっと調べまわったところ
JavaOne 2016時点での情報
- module-info.java に、exports private <モジュール名> と記述
コンパイルすると、エラーとなってしまいます。
src\module-info.java:6: エラー: <identifier>がありません exports private com.torutk.hello; ^ src\module-info.java:6: エラー: パッケージは空であるか、または存在しません <error> exports private com.torutk.hello; ^
JavaDay Tokyo 2017時点での情報
Java Day Tokyo 2017のセッション資料 Modular Development with JDK 9
- module-info.java に、open <モジュール名> (to <モジュール名>)* と記述
opens com.torutk.hello to javafx.fxml;
ということで、module-info.java を次のように記述すると実行できるようになりました。
module com.torutk.hello { requires javafx.controls; requires javafx.fxml; requires javafx.graphics; exports com.torutk.hello; opens com.torutk.hello to javafx.fxml; }
記述量を減らすために、次のように記述してもよいようです。
open module com.torutk.hello { requires javafx.controls; requires javafx.fxml; requires javafx.graphics; }
exportsとopensの指定を、モジュール宣言部にopenとしてしまうことで省略できるのですね。
ただし、これだとどのモジュールへもopenになってしまいます。
ネイティブインストーラーの作成
ここまで来たら、ネイティブインストーラー(WindowsのMSI形式など)を作って、バンドルされるJREがどれだけ小さくなるか確認したくなります。JDK 9のjavapackagerコマンドで、Windows MSI形式インストーラーを作成します。
> javapackager -deploy -native msi -outdir dist -outfile HelloJavaFx ^ --module-path dist --module com.torutk.hello/com.torutk.hello.HelloApp ^ -vendor Takahashi
vendor を指定しなかったときは、OSのログイン名(サインイン名)が使われますが、ASCII文字以外のサインイン名だとエラーになってしまいます。明示的にvendorオプションを指定しておきます。
モジュール化(Jigsaw化)されたアプリケーションの場合は、javapackagerのオプションで、従来の-srcdirオプション、-srcfilesオプションに変えて--module-pathオプション、--moduleオプションを指定します。-appclassオプションでMainクラスを指定していたものは、--moduleオプションでモジュール名 + "/" の続きにメインクラス名を記述すればよいようです。
種類 | MSIファイルサイズ | インストールディレクトリサイズ |
---|---|---|
JDK 9モジュール対応 | 31MB | 90MB |
JDK 9モジュール非対応 | 59MB | 167MB |
モジュール化によって、依存するJREのモジュールだけがバンドルされるようになるので、インストーラーファイルのサイズと実際にインストールされたディレクトリ以下のファイルサイズがそれぞれほぼ半分になりました。