torutkのブログ

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

IntelliJ IDEAでGradleを使ってJPMSプロジェクトの作成

IntelliJ IDEAでGradleを使ってJPMS(モジュールシステム)対応のプロジェクトを作成

JavaのビルドツールGradleが、まもなくリリースされるバージョン6.4で、Java SE 9で導入されたJava Platform Module System(略称JPMS)に対応します。Java SE 9がリリースされた2017年9月から3年近くが経過し、ようやくGradleがJPMS対応されます。

今回は、IntelliJ IDEA上でGradleをビルドツールに使うJPMS対応のプロジェクトを作成する経緯を記します。

開発環境は次です。

項目 内容
OS Windows 10 Pro 64bit 日本語版
JDK Liberica JDK 14 full 64bit
IntelliJ IDEA Community 2020.1.1
Gradle 6.4 RC-4

Liberica JDK 14のインストール

Liberica JDKの提供元 Bell Software社から JDK 14.0.1 Full versionをダウンロードします。

https://bell-sw.com/

bellsoft-jdk14.0.1+8-windows-amd64-full.zip

Full versionはJavaFXを同梱したJDKとなっています。Windows用のLiberica JDKMSIインストーラー形式とZIP形式とが用意されています。開発環境では各種各バージョンのJDKを多数揃える(同居させる)ので、zip版をダウンロードし展開するのがよいでしょう。

IntelliJ IDEA Community版

IntelliJ IDEA Community版(無料)をインストールします。 https://www.jetbrains.com/ja-jp/idea/download/

Gradle 6.4 RC4のインストール

Gradle Build Tool - Releases を開き、[release candidates]リンクを辿り、Install Manually項の[Binary-only]をクリックすると、Gradle 6.4 RC4のバイナリzipファイルをダウンロードします。

gradle-6.4-rc-4-bin.zip

このファイルをマシン上の適切な場所(C:\Program Files\Java\gradle-6.4-rc-4)に展開しました。

IntelliJ IDEAでJDKの設定

プロジェクト作成前に、IntelliJ IDEA上でLiberica JDK 14 full のJDK定義を作成しておきます。

  • [File]メニュー > [Project Structure] で「Project Structure」画面を開き、左側ペインで[Program Settings] > [SDKs]を選択、中側ペインの[+]をクリックし、[Add JDK]を選択して「Select Home Directory for JDK」画面でJDKのインストールディレクトリを指定します。

  • 「Select Home Directory for JDK」画面の右側ペインでName欄に指定したJDKに適切な名称を記入します(例:Liberica JDK 14 full)。

IntelliJ IDEAでJavaアプリケーション(単一モジュール)プロジェクト

JPMSモジュールを指定して実行するアプリケーションを作成します。今回はJPMSの定義、ビルド、実行に着目するため、依存ライブラリは使用しません。

プロジェクトの作成

IntelliJ IDEA上でGradleを使うプロジェクトを新規作成

まず、IntelliJ IDEAのプロジェクト作成機能でGradleのプロジェクトを作成します。

IntelliJ IDEAを起動、新規プロジェクト(Gradle)を作成します。なお、これで作成したプロジェクトはGradleのバージョンが古い(IntelliJ IDEA 2020.1の場合、Gradle 6.1)ので、後の手順で新しいGradleを使うよう設定を変更します。

  • 「New Project」画面の左側ペインで[Gradle]を選択し、右側ペインでProject SDK欄に前の手順で定義したJDK名(例:Liberica JDK 14 full)を選択します。
  • Additional Libraries and Frameworks欄は、[Java]にチェックを付けて、[Next]ボタンをクリックします。
  • Name欄にプロジェクト名(例:HelloJavaFx)を記入、Location欄にプロジェクトの基点ディレクト1を記入
  • Artifact Coordinatesの左端にある▼印をクリックし、詳細設定項目を展開します。
  • GroupId欄に、成果物のグループ識別子(通常代表モジュールのパッケージ名逆順、例:com.torutk.hello)を記入します。
  • ArtifactId欄に、成果物の名前(デフォルトではプロジェクト名が展開済み)を記入します。
  • Version欄に、バージョン名を記入します。
    f:id:torutk:20200505224804p:plain
    IntelliJ IDEA新規プロジェクト(Gradle)の成果物定義画面
Gradleプロジェクトのディレクトリ構成

IntelliJ IDEAで作成したGradleプロジェクトのディレクトリ・ファイル構成は次です。

HelloJavaFx
│  build.gradle
│  gradlew
│  gradlew.bat
│  settings.gradle
│
├─.gradle
│  ├─6.1
│  │  │  gc.properties
│  │  │
│  │  ├─executionHistory
│  │  │      executionHistory.bin
│  │  │      executionHistory.lock
│  │  │
│  │  ├─fileChanges
│  │  │      last-build.bin
│  │  │
│  │  ├─fileHashes
│  │  │      fileHashes.bin
│  │  │      fileHashes.lock
│  │  │
│  │  └─vcsMetadata-1
│  ├─buildOutputCleanup
│  │      buildOutputCleanup.lock
│  │      cache.properties
│  │      outputFiles.bin
│  │
│  ├─checksums
│  │      checksums.lock
│  │
│  └─vcs-1
│          gc.properties
│
├─.idea
│      .gitignore
│      compiler.xml
│      gradle.xml
│      misc.xml
│      workspace.xml
│
├─gradle
│  └─wrapper
│          gradle-wrapper.jar
│          gradle-wrapper.properties
│
└─src
    ├─main
    │  ├─java
    │  └─resources
    └─test
        ├─java
        └─resources
使用するGradleをIntelliJ IDEA同梱のものから別途インストールしたものへ変更

IntelliJ IDEAの[File]メニュー > [Settings]で「Settings」画面を開き、左側ペインで[Buid, Execution, Deployment] > [Build Tools] > [Gradle]を選択、右側ペインで[Gradle Projects]領域内のUse Gradle from欄をデフォルトの'gradle-wrapper.properties' fileからSpecified locationに変更、右隣の欄にGradle 6.4 RC4ディレクトリパスを設定します。

その下のGradle JVM欄は、プロジェクトで使用するJVM(例:Liberica JDK 14 full)を選択します。

[OK]ボタンを押すと、Gradleの設定ファイルとのSyncが実行されます。

  • 既存のGradleプロジェクトでGradleのバージョンを更新する場合、通常は gradle wrapper --gradle-version 6.4-rc-4 と実行して指定バージョンへ更新するようです。
build.gradleファイルの編集

IntelliJ IDEAが生成したbuild.gradle(次に示す)は、JPMS対応前のバージョン用の定義です。

plugins {
    id 'java'
}

group 'com.torutk.hello'
version '0.1.0'

repositories {
    mavenCentral()
}

dependencies {
    testCompile group: 'junit', name: 'junit', version: '4.12'
}

Gradle 6.4のJPMS対応のドキュメント(以下のURL)を参照し、修正をします。 Gradle 6.4-rc-4 Release Notes

GradleプラグインJava一般用からアプリケーション用に変更します。

  plugins {
-     id 'java'
+     id 'application'
  }

実行クラスを含む実行可能モジュールとメインクラスを定義します。

+ application {
+     mainModule = 'com.torutk.hello'
+     mainClass = 'com.torutk.hello.MessageBoard'
+ }

モジュールパス推論をセットします。

  version '0.1.0'

+ java {
+     modularity.inferModulePath = true
+ }

リポジトリ定義、依存関係定義は今回使用しないので削除しておきます。

build.gradle

修正後のbuild.gradleファイルの全体象は次です。

plugins {
    id 'application'
}

group 'com.torutk.hello'
version '0.1.0'

java {
    modularity.inferModulePath = true
}

application {
    mainModule = 'com.torutk.hello'
    mainClass = 'com.torutk.hello.MessageBoard'
}

モジュール定義

src\main\javaディレクトリの下にモジュール定義(module-info.java)を作成します。

HelloJavaFx
└─src
    ├─main
    │  ├─java
    │  │  │  module-info.java

モジュール定義の内容は次です。

module com.torutk.hello {
    requires javafx.graphics;
    opens com.torutk.hello to javafx.graphics;
}
  • 作成するアプリケーションのモジュール名をcom.torutk.helloと定義
  • アプリケーションモジュールcom.torutk.helloは、javafx.graphicsモジュールを使用(requiresの依存関係)
  • このアプリケーションモジュールに含むcom.torutk.helloパッケージは、javafx.graphicsモジュールに対して実行時にのみアクセスを許可(リフレクションでアクセス可能とする)

メインクラスの作成

src\main\javaディレクトリの下に、パッケージcom.torutk.helloに対応するディレクトリを作成し、その中にメインクラスを配置します。

└─src
    ├─main
    │  ├─java
    │  │  │  module-info.java
    │  │  │
    │  │  └─com
    │  │      └─torutk
    │  │          └─hello
    │  │                  MessageBoard.java

メインクラスの最初の雛形ソースコードは次です。

package com.torutk.hello;

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

public class MessageBoard extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        primaryStage.show();
    }
}
  • ここでは空の(真っ白な)ウィンドウを1つ表示するだけのメインクラスを記述

ビルド

では、早速ビルドしてみます。

IntelliJ IDEAのメニューからビルド

[Build]メニュー > [Build Project] を実行します。

23:40:16: Executing tasks ':classes :testClasses'...

> Task :compileJava
> Task :processResources NO-SOURCE
> Task :classes
> Task :compileTestJava NO-SOURCE
> Task :processTestResources NO-SOURCE
> Task :testClasses UP-TO-DATE

BUILD SUCCESSFUL in 1s
1 actionable task: 1 executed
23:40:18: Tasks execution finished ':classes :testClasses'.

メニューからビルドを実行すると、Gradleのタスクのうち classes と testClasses (とその依存タスク)だけを実行しています。 ビルドの結果生成されるディレクトリ・ファイルは次です。クラスファイルのみ生成されています。

├─build
│  ├─classes
│  │  └─java
│  │      └─main
│  │          │  module-info.class
│  │          │
│  │          └─com
│  │              └─torutk
│  │                  └─hello
│  │                          MessageBoard.class
│  │
│  ├─generated
│  │  └─sources
│  │      ├─annotationProcessor
│  │      │  └─java
│  │      │      └─main
│  │      └─headers
│  │          └─java
│  │              └─main
│  └─tmp
│      └─compileJava
Gradleのbuildタスク実行

Gradleペインの中から[Tasks] > [build] > [build] を実行します。 f:id:torutk:20200506234836p:plain

Build結果出力は次です。

23:44:40: Executing task 'build'...

> Task :compileJava
> Task :processResources NO-SOURCE
> Task :classes
> Task :jar
> Task :startScripts
> Task :distTar
> Task :distZip
> Task :assemble
> Task :compileTestJava NO-SOURCE
> Task :processTestResources NO-SOURCE
> Task :testClasses UP-TO-DATE
> Task :test NO-SOURCE
> Task :check UP-TO-DATE
> Task :build

BUILD SUCCESSFUL in 504ms
5 actionable tasks: 5 executed
23:44:41: Task execution finished 'build'.

先ほどのclasses、testClassesタスク以外にも、多数のタスクが実行されているのが分かります。 ビルド結果は次です。

├─build
│  ├─classes
│  │  └─java
│  │      └─main
│  │          │  module-info.class
│  │          │
│  │          └─com
│  │              └─torutk
│  │                  └─hello
│  │                          MessageBoard.class
│  │
│  ├─distributions
│  │      HelloJavaFx-0.1.0.tar
│  │      HelloJavaFx-0.1.0.zip
│  │
│  ├─generated
│  │  └─sources
│  │      ├─annotationProcessor
│  │      │  └─java
│  │      │      └─main
│  │      └─headers
│  │          └─java
│  │              └─main
│  ├─libs
│  │      HelloJavaFx-0.1.0.jar
│  │
│  ├─scripts
│  │      HelloJavaFx
│  │      HelloJavaFx.bat
│  │
│  └─tmp
│      ├─compileJava
│      └─jar
│              MANIFEST.MF

クラスファイルだけでなく、tar、zipファイル、jarファイル、それからシェルスクリプト/バッチファイルなども生成されています。

  • distributions のtar/zipファイルには、アプリケーションのjarファイルと実行用スクリプト/バッチファイルが含まれています。
  • libsのアプリケーションjarファイルは、実行可能JARファイルでかつ実行可能モジュールJARファイルとなっています。
コマンドプロンプトからjavaコマンドで実行

Liberica JDK 14にパスを通したコマンドプロンプトからアプリケーションを実行します。

D:\work\HelloJavaFx> java -p build\libs -m com.torutk.hello
  • モジュールJARファイルのあるディレクトリ(build\libs)を-pオプションで指定
  • 実行可能モジュール名(com.torutk.hello)を-mオプションで指定
配布イメージファイルを展開し中のバッチファイルから実行

build\distributions\HelloJavaFx-0.1.0.zip を適当な場所に展開します。

Liberica JDK 14にパスを通したコマンドプロンプトから、上述の展開した中にあるbin\HelloJavaFx.batを実行します。


  1. ここで指定したディレクトリの下に、gradle、srcなどのディレクトリおよびbuild.gradle、gladlewなどのファイル群が生成されます