torutkのブログ

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

NetBeans 7.2で作成したJavaFXアプリケーション起動の謎

NetBeans 7.2の新規プロジェクト「JavaFX アプリケーション」で作成したプログラムは、JavaFX ライブラリのJARファイルをクラスパスに指定することなく実行できます。

試しに、NetBeansで[ファイル]メニュー>[新規プロジェクト...]で、カテゴリ欄で[JavaFX]を選択、プロジェクト欄で[JavaFXアプリケーション]を選択し、[次へ]ボタンを押します。

これで作成したプロジェクトは、雛形のソースコードとして画面上にボタンが1つ表示するものが生成されています。これをビルドして実行します。NetBeans上であればプロジェクトの設定にJavaFXライブラリ関係が含まれるので実行できるのは当然です。

しかし、このプロジェクトでビルドしたプログラムのJARファイルを、コマンドラインJavaFX関係のJARファイルをクラスパスに指定しなくても起動できます。

C:\work\JavaFXApplication5> java -jar dist\JavaFXApplication5.jar
  :

Windowsエクスプローラ上でJavaFXApplication5.jarファイルをダブルクリックしても起動します。

JavaFXのライブラリをどこから読んでいるのでしょうか?

まず考えられるのは、アプリケーションJARファイルのマニフェストに、JavaFX関係のライブラリが指定されているのではないか、です。
Class-Path:属性に、実行に必要なJARファイルへの相対パスを記載しておくと、別途クラスパスに指定しなくても記載したJARファイルが利用可能になります。

マニフェストを見てみましょう。

Manifest-Version: 1.0
JavaFX-Version: 2.2
implementation-vendor: torutk
implementation-title: JavaFXApplication5
implementation-version: 1.0
JavaFX-Application-Class: javafxapplication5.JavaFXApplication5
JavaFX-Class-Path: 
Created-By: JavaFX Packager
Main-Class: com/javafx/main/Main

うーむ、Class-Path:属性はありませんね。想定が外れました。

と、ここで気になるのは、Main-Class:属性です。実行可能JARファイルでは、mainメソッドを持つクラスをMain-Class:属性に記載しますが、

Main-Class: com/javafx/main/Main

このようなクラスは、今作成したJavaFXプロジェクトにはありません。

ここで、生成されたアプリケーションJARファイルの中に含まれるファイル一覧を見てみます。

C:\work\JavaFXApplication5> jar tf dist\JavaFXApplication5.jar
META-INF/
META-INF/MANIFEST.MF
javafxapplication5/
javafxapplication5/JavaFXApplication5$1.class
javafxapplication5/JavaFXApplication5.class
com/
com/javafx/
com/javafx/main/
com/javafx/main/Main$1.class
com/javafx/main/Main$2.class
com/javafx/main/Main.class
com/javafx/main/NoJavaFXFallback.class

C:\work\JavaFXApplication5> 

なんと、com/javafx/main/Main.class などいくつかアプリケーションプロジェクトのソースファイルにはないクラスが追加されています。

どうやら、NetBeans 7.2のJavaFXアプリケーションプロジェクトで作成するアプリケーションでは、実行時に最初に呼ばれるmainメソッドは、アプリケーション(この例ではJavaFXApplication5クラス)のmainメソッドではなく、com.javafx.main.Mainクラスのmainメソッドになります。

このcom.javafx.main.MainクラスはJDK 7に含まれているものかNetBeansが独自に提供するものかを調べてみました。すると、
[JDK 7インストールディレクトリ]\lib\ant-javafx.jar の中に存在していました。

このMainクラスの中を調べると、JDK 7u6のようにJavaFXライブラリを同梱(cobundled)している場合、[システムプロパティjava.home]\libにある以下のJARファイルを指定しURLClassLoaderを生成しています。

  • jfxrt.jar
  • deploy.jar
  • plugin.jar
  • javaws.jar

これで、JavaFX関係のJARファイルをクラスパスに指定しなくても実行できるわけが分かりました。

このMainクラスを調べてみると、システムプロパティ javafx.verboseがtureのときに、いろいろメッセージを表示するコードがありました。

  • Djavafx.verbose=true を指定して実行してみます。
C:\work\JavaFXApplication5> java -Djavafx.verbose=true 
 -jar dist\JavaFXApplication5.jar
java.version = 1.7.0_06
java.runtime.version = 1.7.0_06-b24
appName = javafxapplication5.JavaFXApplication5
Unable to find preloader class name
preloaderName = null
embeddedArgs = []
commandLineArgs = []
1) Try existing classpath...
===== URL list
file:/C:/work/JavaFXApplication5/dist/JavaFXApplication5.jar
2) Try javafx.runtime.path property...
3) Look for cobundled JavaFX ... [java.home=C:\Program Files\Java\jdk1.7.0\jre
===== URL list
file:/C:/work/JavaFXApplication5/dist/JavaFXApplication5.jar
file:/C:/Program%20Files/Java/jdk1.7.0/jre/lib/jfxrt.jar
file:/C:/Program%20Files/Java/jdk1.7.0/jre/lib/deploy.jar
file:/C:/Program%20Files/Java/jdk1.7.0/jre/lib/plugin.jar
file:/C:/Program%20Files/Java/jdk1.7.0/jre/lib/javaws.jar
Try calling Class.forName(javafxapplication5.JavaFXApplication5) using classLoad
er = java.net.URLClassLoader@7bc221b2
found class: class javafxapplication5.JavaFXApplication5
launchApp: Try calling com.sun.javafx.application.LauncherImpl.launchApplication

Autoconfig of proxy is completed.
JavaFX: using com.sun.javafx.tk.quantum.QuantumToolkit

C:\work\JavaFXApplication5>

ひとまず、ここまで。