torutkのブログ

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

Gradle 7.0 とJavaモジュールシステム

Gradle 7.0 のリリース

2021年4月に Gradle 7.0 がリリースされました。

https://docs.gradle.org/7.0/release-notes.html

この3月にリリースされたJDK 16に対応したほか、Javaモジュールシステム対応が正式機能に昇格しました。Javaモジュールシステム対応は、バージョン6.4(2020年5月リリース)で試験的に導入されましたが、バージョン7.0で正式機能になりました。

これを機に、次を試してみました。

  • Javaモジュールシステムを使用したJavaアプリケーションのビルド
  • ビルド設定を Kotlin で記述
  • gradle init で雛形を生成せずにゼロから設定を記述
  • インターネット非接続での使用
  • JavaFX のライブラリをローカルにインストールして参照

環境の構築

動作環境は次です。

項目 内容
OS Windows 10 Pro 64bit 日本語
JDK Oracle JDK 16.0.1 *1
Gradle Gradle 7.0
JavaFX JavaFX 16

Gradle 7.0 のセットアップ

Gradleのダウンロードページから、Gradle v7.0のバイナリ(binary-only)をダウンロードします。

https://gradle.org/releases/

C:\Program Files\Java フォルダの下に上述で入手したバイナリを解凍し展開します。

C:\Program Files\Java\gradle-7.0

ディレクトリのシンボリックリンク C:\Program Files\Java\gradle を作成します。gradleを複数バージョン抱える際に、環境変数PATH設定をいじらずにシンボリックリンクの変更で切替えています。

C:\Program Files\Java> mklink /D gradle gradle-7.0

環境変数PATHに、C:\Program Files\Java\gradle\bin を追加します。

gradleの実行確認です。

C:\> gradle -version

------------------------------------------------------------
Gradle 7.0
------------------------------------------------------------

Build time:   2021-04-09 22:27:31 UTC
Revision:     d5661e3f0e07a8caff705f1badf79fb5df8022c4

Kotlin:       1.4.31
Groovy:       3.0.7
Ant:          Apache Ant(TM) version 1.10.9 compiled on September 27 2020
JVM:          16.0.1 (Oracle Corporation 16.0.1+9-24)
OS:           Windows 10 10.0 amd64

Javaモジュールシステムで動く Hello アプリケーション

まずは、素のJavaコマンドラインから動くHello Worldアプリケーションを Gradle でビルド・実行します。

プロジェクトディレクトリの作成とビルドスクリプト記述

プロジェクトディレクトリを作成します。

D:\work> mkdir hello_app
D:\work> cd hello_app
D:\work\hello_app> 

ビルドスクリプトを記述します。Kotlin で記述する場合、build.gradle.kts というファイル名で作成します。

plugins {
    application
}

application {
    mainModule.set("com.torutk.hello.app")
    mainClass.set("com.torutk.hello.Main")
}
  • Javaの実行可能プログラムを作成する application プラグイン(Gradleに標準搭載のコアプラグインの一つ)を指定
  • Javaモジュールシステムで実行可能モジュールを設定(モジュール名 com.torutk.hello.app)
  • プログラムのエントリポイントとなるクラスを設定(クラス名 com.torutk.hello.Main)

ソースファイルのディレクトリを構成します。 Gradleのjavaプラグインは、デフォルトでソースファイルがsrc\main\javaディレクトリ下にパッケージ階層に対応して置かれているものとして扱います。

D:\work\hello_app
  +-- build.gradle.kts
  +-- src
        +-- main
              +-- java
                    +-- module-info.java
                    +-- com
                           +-- torutk
                                 +-- hello
                                       +-- Main.java

モジュール定義とプログラム作成

module-info.java

モジュール定義ファイルを記述します。

module com.torutk.hello.app {
}

単純なHelloプログラムなのでデフォルトで使用するモジュールjava.base以外に必要な依存性はないので、モジュール名のみ定義します。

Main.java

コマンドラインから実行し、標準出力にメッセージを出力するだけの簡単なクラス(メインクラス)を記述します。

package com.torutk.hello;

public class Main {
    public static void main(String[] args) {
    System.out.println("Hello, JPMS World, powered by Gradle!");
    }
}

ビルド

D:\work\hello_app> gradle jar
  :

ビルド結果は、build\libsディレクトリにhello_app.jarとして生成されます。

プログラムの実行

Gradleのrunタスクで実行
D:\work\hello_app> gradle run
> Task :run
Hello, JPMS World, powered by Gradle!

BUILD SUCCESSFUL in 1s
3 actionable tasks: 1 executed, 2 up-to-date
コマンドラインから実行
D:\work\hello_app> java -p build\libs -m com.torutk.hello.app

Hello, JPMS World, powered by Gradle!

実行可能モジュールJARファイルが置かれている build\libs ディレクトリを、--module-path(-p)オプションで指定し、実行可能モジュール名を -m オプションで指定してプログラムを実行します。

Javaモジュールシステムで動くJavaFXアプリケーション

JavaFXは、JDK 11以降JDKから分離され独立したライブラリとして提供されています。とはいえ、Liberica JDKやZulu JDKなどJavaFXを同梱しているOpenJDKディストリビューションもあります。

しかし、今回は外部ライブラリをJavaモジュールシステムで組み込み利用するGradleのビルドを行います。そこで、JavaFXが同梱されていないOracle JDK 16にJavaFX 16を組み合わせることとします。

JavaFX 16の環境を準備

JavaFXのリリース提供サイトから、JavaFX SDKをダウンロードします。各OS毎に提供されているので、Windows用をダウンロードします。 https://gluonhq.com/products/javafx/

ダウンロードしたSDKを展開します。今回は、C:\Program Files\Java\JavaFX の下に展開します。

C:\Program Files\Java\JavaFX\javafx-sdk-16

モジュール定義とプログラム作成

module-info.java

JavaFXのライブラリを使用するので、モジュール定義に追記します。

module com.torutk.hello.app {
    requires javafx.graphics;
    opens com.torutk.hello to javafx.graphics;
}
Main.java

JavaFXアプリケーション(空のウィンドウにタイトル文字列を設定)

package com.torutk.hello;

import javafx.application.Application;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) {
    primaryStage.setTitle("Hello, JPMS JavaFX World!");
    primaryStage.show();
    }
}

ビルドスクリプト記述

JavaFXのライブラリを参照する設定を追記します。

fileTree で絶対パス指定
plugins {
    application
}

application {
    mainModule.set("com.torutk.hello.app")
    mainClass.set("com.torutk.hello.Main")
}

dependencies {
    implementation(fileTree("C:/Program Files/Java/JavaFX/javafx-sdk-16/lib"))
}

dependencies の定義に、fileTreeでJavaFXのjarファイル群があるフォルダを指定します。 この記述は、どのjarファイルを参照しているかまでは記述していません。

flatDir で絶対パス指定+JARファイル指定
plugins {
    application
}

application {
    mainModule.set("com.torutk.hello.app")
    mainClass.set("com.torutk.hello.Main")
}

repositories {
    flatDir {
    dirs("C:/Program Files/Java/JavaFX/javafx-sdk-16/lib")
    }
}

dependencies {
    implementation("javafx:javafx.graphics")
    implementation("javafx:javafx.base")
}

repositoriesの定義にJavaFXのjarファイル群があるフォルダを指定します。 dependenciesでimplementationに使用するJARファイルを指定します。 ここでは、直接使用するJARの他に間接的に使用するJARも指定します。

絶対パスの記述をプロパティに追い出す

ビルドスクリプト絶対パス記述をすると、他のマシン間での共有が難しいので(例えばWindows絶対パスUnixと異なる)、プロパティに追い出します。

gradle.properties に絶対パスを定義

gradle.propertiesにJavaFXディレクトリを記述します。 gradle.propertiesは、ユーザーホームの.gradleディレクトリ下あるいはプロジェクトディレクトリに配置されます。 ユーザーホームはWindowsの場合、%USERPROFILE% となります。

javafx16 = C:/Program Files/Java/JavaFX/javafx-sdk-16/lib
build.gradle.kts でプロパティを参照
plugins {
    application
}

application {
    mainModule.set("com.torutk.hello.app")
    mainClass.set("com.torutk.hello.Main")
}

val javafx16: String by project

repositories {
    flatDir {
    dirs("$javafx16")
    }
}

dependencies {
    implementation("javafx:javafx.graphics")
    implementation("javafx:javafx.base")
}

ビルドスクリプト(Kotlin)では、gradle.propertiesに定義したプロパティを参照する場合、

val javafx16: String by project

とプロパティを委譲で定義します。 プロパティがないと、エラーとなります(次のエラーメッセージ)。

* What went wrong:
Cannot get non-null property 'javafx16' on root project 'hello_app' as it does not exist

プログラムの実行

Gradleのrunタスクでの実行
D:\work\hello_app> gradle run
コマンドラインでの実行
D:\work\hello_app> java -p build\libs;"C:\Program Files\Java\JavaFX\javafx-sdk-16\lib" -m com.torutk.hello.app

その他

ソースファイルをUTF-8とする場合

Gradleは、(というよりjavacコマンドは)ソースファイルがデフォルトエンコーディングWindows 10日本語版ならWindows-31j)で記述されていることを前提とします。 そのため、UTF-8で記述されたソースファイルをWindows上でビルドすると、ソースファイルのリテラル等に記述されたUTF-8マルチバイト文字コードがエラーとなります。

そのときは、ビルドスクリプトに次の記述を追記します。

tasks.withType<JavaCompile>() {
    options.encoding = "UTF-8"
}

Windowsでネットワークドライブ切断時のエラー

Windows上でgradle 7.0を使用するとき、ネットワークドライブを割当てており、その接続が切断されているとエラーになります。

gradle 7.0.1で修正される予定です。

*1:OTNライセンスの下での使用