OpenJFX11 + OpenJDK11 + Maven で JavaFX を動かす

前回のエントリーはOpenJFXとOpenJDKでJavaFXを動かそうというものでした。

skrb.hatenablog.com

でも、OpenJFX SDKにパスを通さなくてはいけないなど、ちょっとめんどうだったのもたしか。

そんなおり、GluonのJoahn VosさんがOpenJFXをMavenでも使えるようにプルリク出してくれました。

github.com

この結果、Maven CentralにOpenJFXが登録されました!!

さっそく使ってみましょう。

サンプルコードはこちら。

package net.javainthebox.hello;

import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.stage.Stage;

public class Hello extends Application {
    @Override
    public void start(Stage stage) throws Exception {
        var label = new Label("Hello, JavaFX + Maven!");
        label.setAlignment(Pos.CENTER);
        var scene = new Scene(label, 200, 50);
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String... args) {
        launch(args);
    }

}

JavaFXHello Worldです。

さて、これをコンパイル、実行するためのpom.xmlがこちら。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>net.javainthebox</groupId>
    <artifactId>hello</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>10</maven.compiler.source>
        <maven.compiler.target>10</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-controls</artifactId>
            <version>11-ea+19</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.7.0</version>
                <configuration>
                    <release>11</release>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.6.0</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>java</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <mainClass>net.javainthebox.hello.Hello</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

このサンプルではjavafx.controlsモジュールを使用しているので、dependencyにはjavafx.controlsを指定しています。Maven Centralではモジュールのピリオドをハイフンで置き換えた名前になっています。

javafx.controlsはjavafx.graphics、javafx.baseに依存しているので、それらも自動的にロードされます。
これ以外にjavafx.fxml、javafx.media、javafx.swing、javafx.webモジュールもちゃんと登録されています。

では、まずはコンパイルしてみましょう。

C:\hello>mvn clean compile
[INFO] Scanning for projects...
[INFO]
[INFO] -----------------------< net.javainthebox:hello >-----------------------
[INFO] Building hello 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ hello ---
[INFO] Deleting C:\Users\yuichi\Desktop\hello\target
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ hello ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory C:\Users\yuichi\Desktop\hello\src\main\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.7.0:compile (default-compile) @ hello ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to C:\Users\yuichi\Desktop\hello\target\classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.103 s
[INFO] Finished at: 2018-07-25T21:44:22+09:00
[INFO] ------------------------------------------------------------------------

C:\hello>

あっさり成功しました。もちろん、初回はモジュールのダウンロードがあるはずです。

では、実行してみましょう。

C:\hello>mvn exec:java
[INFO] Scanning for projects...
[INFO]
[INFO] -----------------------< net.javainthebox:hello >-----------------------
[INFO] Building hello 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- exec-maven-plugin:1.6.0:java (default-cli) @ hello ---

ここまで表示されれば、フレームが表示されているはずです。
OpenJFX SDKを使うよりは、とても簡単にJavaFXのアプリケーションを書けるようになりました。

ところで、JavaFXはネイティブライブラリが必要です。Maven Centralを見てみると、やっぱりプラットフォームごとに分けられてました。下のリンクはjavafx.graphicsのものです。

Central Repository: org/openjfx/javafx-graphics/11-ea+19

pom.xmlを見てみると、プラットフォームによって該当するJARファイルも依存があるように書かれてますね。

現状の問題点

Mavenで実行するとき、exec:javaであれば問題ないのですが、exec:execで別プロセスとして実行させると以下のようなメッセージを出して、実行ができません。

C:\Users\yuichi\Desktop\hello>mvn exec:exec
[INFO] Scanning for projects...
[INFO]
[INFO] -----------------------< net.javainthebox:hello >-----------------------
[INFO] Building hello 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- exec-maven-plugin:1.6.0:exec (default-cli) @ hello ---
エラー: JavaFXランタイム・コンポーネントが不足しており、このアプリケーションの実行に必要です
[ERROR] Command execution failed.
org.apache.commons.exec.ExecuteException: Process exited with an error: 1 (Exit value: 1)
    at org.apache.commons.exec.DefaultExecutor.executeInternal (DefaultExecutor.java:404)
    at org.apache.commons.exec.DefaultExecutor.execute (DefaultExecutor.java:166)

ロードされたクラスを調べてみたのですが、Applicationクラスはロードされているものの、その他のJavaFXに関連するクラスがロードされていません。もうちょっと調べてみようと思ってます。