ScalaからJavaFXを利用する

ScalaからJavaFxを利用したい。ScalaならScalaFxを利用するべきなのでは?と思うかもしれないが、そこは一旦気にしないで欲しい。

jarファイルが実行できない

プロジェクトの依存関係にJavaFXを追加し、assemblyでjarアーカイブをビルドした。 このjarを実行すると、JavaFXコンポーネントが足りないと言われて終了してしまう。

このjarファイルはJavaFXを参照してはいるが、JavaFX本体は埋め込まれていないと推察できる。

一方で、sbt runだったら問題なく実行できることから、JavaFXの本体はこのマシンのどこかに存在していて、sbtはその場所を知っているはずである。 しかもaptでOpenJFXパッケージをインストールする前から動作したので、sbtがJFXをどこからかフェッチしてきて実行しているということである。

さらに、sbtがどこからパッケージをダウンロードしているのかも謎だ。 マニュアルにはレジストリの指定方法とか書いてあったかな? Scalaとは無関係にJavaのパッケージにも中央集権的なレジストリがあるのかも。

しばらく調べていると、StackOverflowに以下のような質問を見つけた。

JavaFX 11 : Create a jar file with Gradle

どうやらJavaFXはちゃんと埋め込まれているが、バージョン11特有の不具合で、エントリポイントになるクラスがApplicationを継承していると問題が起こるようだった。

適当にMain関数のラッパーを書いて、build.sbtにエントリポイントを記述すると、無事実行することができた。

MediaPlayerが作成できない

JavaFXのMediaPlayerが作成できないエラーに遭遇した。これまではopenjfx11を使っていたが、現在の開発環境にインストールされている新しいバージョンのコーデックと互換性がない。特にJavaFX11に固執する理由もなかったので、最新のLTS版であるバージョン20を使うことにした。

sbt runで実行できない

sbt の対話型環境から複数回runすると、最初の実行のみ期待通りに動作し、2回目以降はモジュールのロードに失敗していまう。これは解決していないが、毎回jarにバンドルすれば一応実行はできるので、後回しにすることにした。

ファイルが衝突する

また、jarアーカイブを作成する際に、大量のファイルが衝突した。どうやらjarアーカイブの中には1つしか存在できない特別なファイルがあり、複数のjarをまとめて一つのjarを作るときには、それらをうまくマージして一つにしないといけないようだった。