JavaFXアプリケーションをMavenプロジェクトで作り直す

前回作成したパスワード管理ツールをMavenプロジェクトで作り直し、jarファイルを作成するところまでを行います。

なお、今回からスペックの関係上OSがUbuntuになってますが、基本的な手順は変わらないはずです。

環境

  • Ubuntu 20.04
  • vscode
  • JDK11

プロジェクト作成

mvn archetype:generate コマンドでプロジェクトを作成します。

入力ウィザードで以下を求められるので適当に入力します。

  • groupId
  • artifactId
  • version
  • package
mvn archetype:generate
[INFO] Scanning for projects...
[INFO] 
[INFO] ------------------< org.apache.maven:standalone-pom >-------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] --------------------------------[ pom ]---------------------------------
[INFO] 
[INFO] >>> maven-archetype-plugin:3.2.1:generate (default-cli) > generate-sources @ standalone-pom >>>
(省略)
Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): 1854: 
Choose org.apache.maven.archetypes:maven-archetype-quickstart version: 
1: 1.0-alpha-1
2: 1.0-alpha-2
3: 1.0-alpha-3
4: 1.0-alpha-4
5: 1.0
6: 1.1
7: 1.3
8: 1.4
Choose a number: 8: 
Define value for property 'groupId': com.swapps
Define value for property 'artifactId': PasswordManager
Define value for property 'version' 1.0-SNAPSHOT: : 
Define value for property 'package' com.swapps: : 
Confirm properties configuration:
groupId: com.swapps
artifactId: PasswordManager
version: 1.0-SNAPSHOT
package: com.swapps
 Y: : Y
 (省略)

ビルド設定

プロジェクトを実行するための設定をpom.xmlに記載します。

実行するための設定

以下を build -> plugins へ exec-maven-pluginを有効にする設定を追加します。これにより mvn exec:java で実行することができます。

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>exec-maven-plugin</artifactId>
    <version>1.2.1</version>
    <configuration>
        <mainClass>com.swapps.App</mainClass>
    </configuration>
</plugin>

パッケージングの設定

maven-assembly-plugin と maven-dependency-plugin を追加します。これにより mvn package を実行したときに jar ファイルが出力されるようになります。

<plugin>
  <artifactId>maven-assembly-plugin</artifactId>
  <version>3.1.1</version>
  <configuration>
    <appendAssemblyId>false</appendAssemblyId>
    <descriptorRefs>
      <descriptorRef>jar-with-dependencies</descriptorRef>
    </descriptorRefs>
    <archive>
      <manifest>
        <mainClass>com.swapps.App</mainClass>
      </manifest>
    </archive>
  </configuration>
  <executions>
    <execution>
      <id>make-assembly</id> 
      <phase>package</phase> 
      <goals>
        <goal>single</goal>
      </goals>
    </execution>
  </executions>
</plugin>

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId></artifactId>
  <version>3.1.1</version>
  <executions>
    <execution>
      <id>copy-dependencies</id>
      <phase>package</phase>
      <goals>
        <goal>copy-dependencies</goal>
      </goals>
      <configuration>
        <!-- configure the plugin here -->
      </configuration>
    </execution>
  </executions>
</plugin>

ライブラリを追加

このアプリケーションで使用するライブラリを dependencies へ追加します。

  • jackson-databind
  • javafx-controls
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.13.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.openjfx/javafx-controls -->
<dependency>
  <groupId>org.openjfx</groupId>
  <artifactId>javafx-controls</artifactId>
  <version>18-ea+9</version>
</dependency>

実装

実装に関しては以下のソースコードをコピーして、App.java の package以下に貼り付け、データファイルのパスだけ同階層のディレクトリから読み込むように変更しました。

https://www.s-watanabe.work/2022/01/windowsjavafx.html#toc_headline_11
Files.readAllLines(Paths.get("./data.json"))

動作確認

ターミナルを開いて mvn exec:java コマンドを実行すればアプリケーションを実行できます。

jarファイル作成

mvn clean package コマンドでビルドすることにより、targetディレクトリ下に jarファイルが生成されます。

$ mvn clean package
(省略)
[INFO] Building jar: ./PasswordManager/target/PasswordManager-0.1.jar
(省略)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

jarファイル動作確認

jarファイルを実行

ここで少しハマりました。単純にjarファイルを実行しようとすると以下のエラーが発生します。

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

どうやら生成したjarファイルの中に openjfx のライブラリは含まれず、これはjarファイル実行時に別で読み込む必要があるらしいです。

確かに mvn clean package を実行したときに以下の警告が発生していました。

[INFO] --- maven-assembly-plugin:3.1.1:single (make-assembly) @ PasswordManager ---
[WARNING] Failed to build parent project for org.openjfx:javafx-controls:jar:18-ea+9
[WARNING] Failed to build parent project for org.openjfx:javafx-controls:jar:18-ea+9
[WARNING] Failed to build parent project for org.openjfx:javafx-graphics:jar:18-ea+9
[WARNING] Failed to build parent project for org.openjfx:javafx-graphics:jar:18-ea+9
[WARNING] Failed to build parent project for org.openjfx:javafx-base:jar:18-ea+9
[WARNING] Failed to build parent project for org.openjfx:javafx-base:jar:18-ea+9
[WARNING] Artifact: PasswordManager:jar:0.1 references the same file as the assembly destination file. Moving it to a temporary location for inclusion.

なぜ openjfx だけこのようになってしまうのかは調査中です。

軽視していましたが、このままでは実行できないので openjfx を別途導入します。

openjfxをインストール

apt-getでインストールします。

$ sudo apt-get install openjfx

インストールしたら dpkg コマンドで lib ディレクトリの位置を確認します。

dpkg -L openjfx

モジュールを指定して jarファイルを実行

java -jar -p /usr/share/openjfx/lib --add-modules javafx.controls PasswordManager-0.1.jar
  • --module-path [-p] … 追加で読み込むモジュールのパス
  • --add-modules … 追加で読み込むモジュール名

一応はこれで実行できました。

QuantumRendererが発生する場合

はじめ JavaFX公式ページ から、SDKをダウンロード/解凍し、中のライブラリを指定し試しましたが QuantumRendererエラーが発生しうまく行きませんでした。

$ java -jar -p javafx/lib --add-modules javafx.controls PasswordManager-0.1.jar 
Graphics Device initialization failed for :  es2, sw
Error initializing QuantumRenderer: no suitable pipeline found
java.lang.RuntimeException: java.lang.RuntimeException: Error initializing QuantumRenderer: no suitable pipeline found
	at javafx.graphics/com.sun.javafx.tk.quantum.QuantumRenderer.getInstance(QuantumRenderer.java:283)
	at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.init(QuantumToolkit.java:254)
	at javafx.graphics/com.sun.javafx.tk.Toolkit.getToolkit(Toolkit.java:264)
	at javafx.graphics/com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:291)
	at javafx.graphics/com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:163)
	at javafx.graphics/com.sun.javafx.application.LauncherImpl.startToolkit(LauncherImpl.java:659)
	at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:410)
	at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:364)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1051)
Caused by: java.lang.RuntimeException: Error initializing QuantumRenderer: no suitable pipeline found
	at javafx.graphics/com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.init(QuantumRenderer.java:95)
	at javafx.graphics/com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.java:125)
	at java.base/java.lang.Thread.run(Thread.java:829)
Exception in thread "main" java.lang.reflect.InvocationTargetException
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1051)
Caused by: java.lang.RuntimeException: No toolkit found
	at javafx.graphics/com.sun.javafx.tk.Toolkit.getToolkit(Toolkit.java:276)
	at javafx.graphics/com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:291)
	at javafx.graphics/com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:163)
	at javafx.graphics/com.sun.javafx.application.LauncherImpl.startToolkit(LauncherImpl.java:659)
	at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:410)
	at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:364)
	... 5 more

ソースコード

https://github.com/s-watanabe-apps/javafx-password-manager.git

コメント

このブログの人気の投稿

docker-compose up で proxyconnect tcp: dial tcp: lookup proxy.example.com: no such host

docker-compose で起動したweb、MySQLに接続できない事象

【PHP】PHP_CodeSnifferを使う(コーディングルールのカスタマイズ)