torutkのブログ

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

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

はじめに

これまでにNetBeans 8.2/JDK 8のAntプロジェクト(種類はJavaFXアプリケーション)で作成したJavaFXアプリケーションを、JDK 11に対応させようと試みました。

NetBeans は間もなくリリース予定のNetBeans 10のテストバージョン(vc4)で、OpenJDK 11.0.1とJavaFX 11.0.1を使います。

 今回はアプリケーション側のモジュール対応は行いません。移行後に段階的にモジュール対応を進めます。

最初の試み

まずは、JDK 11からJavaFXが分離したのに伴い、JavaFX 11を別途インストールしマシン上に展開、NetBeansのプロジェクト設定でライブラリとしてこのJavaFXを指定する方針で進めました。

 

JavaFX 11.0.1をダウンロードし、NetBeansのライブラリ定義に加え、既存のJavaFXアプリケーションのプロジェクトにクラスパスとして追加します。

コンパイルは通りますが、実行すると

JavaFX deployment library not found in active JDK.
Please check that the JDK is correctly installed and its version is at least 7u4 on Mac or 7u6 on other systems.

とエラーになってしまいます。NetBeansのビルド定義には、JDKの中にあるJavaFXライブラリの場所を探すコードがあり、見つからないと上述のようにエラーとなってしまいます。

この問題を解決するには、NetBeansが生成したビルド定義に大分手を入れる必要があります。この試みは挫折とします。

次の試み

次は、NetBeansでプロジェクトを新規に作り直す方法で進めます。

既存のディレクトリにNetBeansで新規プロジェクトを作成するとエラーになるので、新しいディレクトリにプロジェクトを作成します。

プロジェクト種類をJavaFXアプリケーションで新規作成しようとするとエラー

このとき、プロジェクトの種類をJavaFXアプリケーションとすると、

Failed to automatically set-up a JavaFX Platform.
Please go to Platform Manager, create a non-default Java SE platform, then go to the JavaFX tab,
enable JavaFX and fill in the paths to valid JavaFX SDK and JavaFX Runtime.

とエラーになります。

プロジェクト種類をJavaアプリケーションで新規作成するとビルドはOKだが実行エラー

そこで、プロジェクト種類をJavaアプリケーションとして新規作成します。そこに既存のソースコードを追加し、ライブラリにJavaFX 11を追加します。

これでビルドは成功しますが、アプリケーションを実行するとエラーとなってしまいます。

エラー: JavaFXランタイム・コンポーネントが不足しており、このアプリケーションの実行に必要です

--add-modulesでJavaFXモジュールを指定して実行エラー回避

解決方法は、javaの実行時のJVMオプションで、--add-modules=javafx.controls のようにアプリケーションから利用するJavaFXのモジュールを指定します。FXMLを使うアプリケーションの場合は、--add-modules=javafx.controls,javafx.fxml のように指定します。

Getting Started with JavaFX 11

なぜ--add-modulesでJavaFXモジュールを指定しなければならないか

ですが、なぜJavaFXのライブラリ(JARファイル)をクラスパスで指定しているのにエラーとなってしまうのか不思議でした。

いろいろ調べてみたところ、次のメーリングリストでその原因が言及されていました。

launching JavaFX in 11

これによると、実行時のエラーはjavaコマンドが最初に参照するメインクラスがJavaFXのApplicationクラスを継承している場合に発生します。javaコマンドがメインクラスをロードする際に、メインクラスが継承しているスーパークラスもロードする必要があります。しかしJavaFXのApplicationクラスがスーパークラスの場合、javafx.graphicsモジュールを探しに行って存在しない場合、クラスパスを探すことなくエラーとなります。

Mainクラスでjavafx.application.Applicationクラスの継承をやめる

試しに、メインクラスでJavaFXのApplicationクラスを継承するのをやめて、mainメソッドの中でJavaFXのApplicationを継承する別クラスを初期化するコードを呼ぶように修正したところ、--add-modulesの指定をせずに実行できるようになりました。

まとめ

  •  NetBeansJavaFXアプリケーション・プロジェクトは、JavaFXが分離したJDKOracle JDK 11以降およびOpenJDK)には対応できない
  • NetBeansJavaアプリケーション・プロジェクトでJavaFXアプリケーションをビルドする際は、JavaFX 11を別途ダウンロードしマシン上に配置し、NetBeansのライブラリ定義を追加し、プロジェクトからJavaFXライブラリを参照する(クラスパスとして参照)
  • NetBeansJavaアプリケーション・プロジェクトでJavaFXアプリケーションを実行する際は、メインクラスにJavaFXのApplicationクラスを継承させず、別クラスで継承し、メインクラスのmainメソッドにはその別クラスを初期化するコードを記述する。