Java Gradle入門

code html digital coding web 1076536

Gradleって何?という方のためにGradleの概要、インストールと設定、代表的なコマンド、チュートリアルで構成しています。

目次

Gradleとは

オープンソースのJavaアプリケーション用ビルドツール.Mavenは設定ファイルをXMLで記述するのに対し,GradleはGroovyで記述できる.そのため柔軟性と可読性が高い.

Groovyのインストール

Gradleの利用だけならGroovyは不要.GradleにはGroovyも含まれている.但し,Groovy自体で開発も出来る環境を作るためGroovyも入れておく.

Macの場合はbrewでインストール出来る

brew install groovy
% exec $SHELL -l
% groovy -v
Groovy Version: 4.0.7 JVM: 18.0.1.1 Vendor: Oracle Corporation OS: Mac OS X

Gradleのインストール

Macの場合はBrewでインストール出来る.

brew install gradle

バージョンの確認

% gradle -v
Welcome to Gradle 7.6!
Here are the highlights of this release:
 - Added support for Java 19.
 - Introduced `--rerun` flag for individual task rerun.
 - Improved dependency block for test suites to be strongly typed.
 - Added a pluggable system for Java toolchains provisioning.
For more details see https://docs.gradle.org/7.6/release-notes.html
------------------------------------------------------------
Gradle 7.6
------------------------------------------------------------
Build time:   2022-11-25 13:35:10 UTC
Revision:     daece9dbc5b79370cc8e4fd6fe4b2cd400e150a8
Kotlin:       1.7.10
Groovy:       3.0.13
Ant:          Apache Ant(TM) version 1.10.11 compiled on July 10 2021
JVM:          18.0.1.1 (Oracle Corporation 18.0.1.1+2-6)
OS:           Mac OS X 13.1 aarch64

ターミナルからのプロジェクトの作成

% mkdir gradle-app
% cd gradle-app
% gradle init --type java-library

以下のように対話形式でプロジェクトの設定を入力します.

Starting a Gradle Daemon (subsequent builds will be faster)
Select build script DSL:
  1: Groovy
  2: Kotlin
Enter selection (default: Groovy) [1..2] 1
Generate build using new APIs and behavior (some features may change in the next minor release)? (default: no) [yes, no] no
Select test framework:
  1: JUnit 4
  2: TestNG
  3: Spock
  4: JUnit Jupiter
Enter selection (default: JUnit Jupiter) [1..4] 4
Project name (default: gradle-app): gradle-app
Source package (default: gradle.app): gradle.app
> Task :init
Get more help with your project: https://docs.gradle.org/7.6/samples/sample_building_java_libraries.html
BUILD SUCCESSFUL in 1m 56s
2 actionable tasks: 2 executed

gradle initコマンド

  • gradleでは gradle タスク名の形式で実行します.
  • ここでは タスク名としてinitを指定して実行しました.
  • initはプロジェクトの基本的なファイルやフォルダを生成します.
  • --typeは生成するプロジェクトのタイプを指定します.
  • ここではjava-libraryを指定しました.これはjavaのプロジェクトを指します.
  • 他にもGroovyやScalaのプロジェクトファイルもサポートされています.
  • --typeを省略した場合,Gradleプロジェクトの基本的なファイルだけが生成されます.

Gradleタスク

  • Gardleの処理はタスクを使って実行します.
  • タスクは実行する処理をまとめた単位です.
  • タスクにはGradleがデフォルトで用意しているものと,自分で作成できるものがあります.
  • プロジェクトのコンパイルや実行もタスクで実行します.

フォルダ構成

% tree -a
.
└── gradle-app
    ├── .gitattributes
    ├── .gitignore
    ├── .gradle
    │·· └── file-system.probe
    ├── gradle
    │·· └── wrapper
    │··     ├── gradle-wrapper.jar
    │··     └── gradle-wrapper.properties
    ├── gradlew
    ├── gradlew.bat
    ├── lib
    │·· ├── build.gradle
    │·· └── src
    │··     ├── main
    │··     │·· ├── java
    │··     │·· │·· └── gradle
    │··     │·· │··     └── app
    │··     │·· │··         └── Library.java
    │··     │·· └── resources
    │··     └── test
    │··         ├── java
    │··         │·· └── gradle
    │··         │··     └── app
    │··         │··         └── LibraryTest.java
    │··         └── resources
    └── settings.gradle
フォルダ名説明
.gradleタスクで生成されたファイルの保存先
srcソースコード
build.gradleGradleのビルドファイル.プロジェクトのビルド設定を記述する.
gradlew, gradlew.batGradleのコマンドファイル
settings.gradleGradleの設定情報を記述する
gradle要確認

src フォルダ

  • src配下にはmainとtestが作成されている.
  • mainはアプリケーションのコードの配置場所
  • testはユニットテストのコードの配置場所
  • src配下の構成はsrc/main or test/java/パッケージ名でMavenと同じ
  • init時に--type jaav-libraryオプションをつけたので,src配下にJava用のサンプルコードが自動生成されている.

ビルド関連ファイル

  • build.gradle
    • ビルドの内容を記述します.Groovyを使って実行する処理を記述します.
  • settings.gradle
    • ビルド時の設定情報を記述します.ビルドを実行する前に読み込まれます.必要なライブラリの読み込みなどを記述します.

build.gradleの中身をチェック

/*
 * This file was generated by the Gradle 'init' task.
 *
 * This generated file contains a sample Java library project to get you started.
 * For more details take a look at the 'Building Java & JVM projects' chapter in the Gradle
 * User Manual available at https://docs.gradle.org/7.6/userguide/building_java_projects.html
 */
plugins {
    // Apply the java-library plugin for API and implementation separation.
    id 'java-library'
}

repositories {
    // Use Maven Central for resolving dependencies.
    mavenCentral()
}

dependencies {
    // Use JUnit Jupiter for testing.
    testImplementation 'org.junit.jupiter:junit-jupiter:5.9.1'

    // This dependency is exported to consumers, that is to say found on their compile classpath.
    api 'org.apache.commons:commons-math3:3.6.1'

    // This dependency is used internally, and not exposed to consumers on their own compile classpath.
    implementation 'com.google.guava:guava:31.1-jre'
}

tasks.named('test') {
    // Use JUnit Platform for unit tests.
    useJUnitPlatform()
}
  • plugins
    • 適用するプラグインを記述します.
  • repositories
    • 参照するリポジトリを記述します.
    • mavenCentral()はセントラルリポジトリの情報を返します.
  • dependencies
    • 依存するライブラリを記述します.
    • ライブラリを参照するタイミングとライブラリ (groupId:artifactId)名のペアで記述します.
  • tasks
    • タスク名と実際に実行するタスクを記述します.

ソースファイルの中身をチェックする

src配下に作成されるコードはいずれもダミーコードの位置づけです.中身はほとんどありません.Library.javaはmainメソッドも実装されていないため,このままでは実行できません.

Library.java

/*
 * This Java source file was generated by the Gradle 'init' task.
 */
package gradle.app;

public class Library {
    public boolean someLibraryMethod(
) {
        return true;
    }
}

LibraryTest.java

/*
 * This Java source file was generated by the Gradle 'init' task.
 */

package gradle.app;

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

class LibraryTest {
    @Test void someLibraryMethodReturnsTrue() {
        Library classUnderTest = new Library();
        assertTrue(classUnderTest.someLibraryMethod(), "someLibraryMethod should return 'true'");
    }
}

Intellijj IDEAでGradleプロジェクトを作成する

プロジェクトの作成

画面のように入力して新規作成します.

Gradle7.4ではJDK7からJDK16までしかサポートしていないとの警告が表示されます.

JDK選択のダイアログを開きます.

Add JDKを選択します.

Version 17で利用可能なAmazon Correttoを選択します.OracleのJDKを入れたければ事前にOracleのサイトからインストーラーをダウンロードしてインストールしておけば良いと思います.

改めてCreateボタンを押します.

プロジェクトが作成されました.

ビルド関連ファイル

build.gradle

plugins {
    id 'java'
}

group 'org.example'
version '1.0-SNAPSHOT'

repositories {
    mavenCentral()
}

dependencies {
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
}

test {
    useJUnitPlatform()
}

settings.gradle

rootProject.name = 'gradle-sample-intellij'

Run Configurationの追加

右上のAdd Configurationボタンをクリックします.

Gradleを選択します.

Run/Debug Configuration画面が開きます.

Runからbuildを選択します.

Nameには自由に名前をつけます.最後にOKを押して完了します.

build taskを実行

先程作成したRun/Debug Configurationが選択されている状態で三角ボタンを押して実行します.

以下のようにログが出力されます.

20:22:08: Executing 'build'...
Starting Gradle Daemon...
Gradle Daemon started in 718 ms
> Task :compileJava
> Task :processResources NO-SOURCE
> Task :classes
> Task :jar
> 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 2s
2 actionable tasks: 2 executed
20:22:11: Execution finished 'build'.

ビルドが成功しました.

gradle-guiは4.7では利用不可

以前のGradleのバージョンではgradle --guiでグラフィカルユーザーインターフェースによる設定画面が使えたようですが,ver4.7では利用不可になっているようです.

% gradle --gui                                                                   
Unknown command-line option '--gui'.

build.gradleの基本を理解する

Gradleのbuild.gradleはGroovyのDSLで記述する

  • Gradleはbuild.gradleに書かれているコードを実行することでビルドの処理を行う仕組み.
  • build.gradleの書き方が重要
  • Gradleのbuild.gradleはGroovyそのもので記述はしない
  • GradleはGroovyベースのDSLで記述する

DSLは特定用途言語

  • DSLは日本語ではドメイン固有言語と略される
  • 特定の用途に限定された言語.
  • ベースになる言語を特定用途に限定してアレンジしたもの
  • 従って,Gradleで使われている言語はGroovyをベースにして作成されたGradle DSLで記述するといのが正しい理解

Gradleのタスクを理解する

  • タスクは実行したい処理をひとまとめにしてコマンドとして実行出来るようにしたもの
task タスク名 {
  実行する処理
}

タスクはターミナルからgradle タスク名で実行出来ます.

タスクを実行する

タスクの簡単なサンプルを作成します.build.gradleに以下を追加します.追加するのはターミナルから作成したプロジェクトまたはIntellij IDEAから作成したプロジェクトのどちらでも構いません.

task greeting {
    doLast {
        println();
        println("Hello, World!");
    }
}

プロジェクト直下で実行します.以下のように表示されれば成功です.

% gradle greeting
> Task :greeting
Hello, World!
BUILD SUCCESSFUL in 496ms
1 actionable task: 1 executed

taskにはこのようにビルドやコンパイルだけではなく,単にメッセージを出力するだけのようなものも作成できます.

以下のように-qオプションをつけるとquiet modeで実行できます.quiet modeでは例外発生などの重要な問題以外の表示が抑制されます.

gradle -q greeting

タスクはアクションの組み合わせ

  • doLast{ }で記述した内容は予め用意されているdoLast{ }メソッドの内容を上書きする.
  • doLastはタスクのアクションリストの最後に処理を追加する.
  • アクションリストはアクション(実行する処理)を管理するリスト.
  • タスクは内部にさまざまなアクションを所有している.
  • タスクを実行すると,用意されたアクションが順番に実行される.
  • このアクションを管理しているのがアクションリスト.
  • タスクはアクションの組み合わせ.
  • doFirstは最初に実行されるアクション.
  • doLastは最後に実行されるアクション.

doLastとdoFirstの動きを確認してみます.build.gradleに以下を追加します.

task actionOrder {
    doLast {
        println("This is last action.");
    }
    doFirst {
        println("This is first action.");
    }
}

実行してみます.

% gradle actionOrder -q
This is first action.
This is last action.

記述した順番に関わらず,doFirst, doLastの順番に実行されました.

taskにパラメータを渡す

タスクにはパラメータを渡すことが出来ます.

task count {
    doLast {
        def total = 0;
        for (def i in 1..num.toInteger()) {
            total += i
        }
        printf("total: %s%n", total);
    }
}

以下のように -P変数名=xxxで値を渡せます.

% gradle -q count -Pnum=100
total: 5050

コマンドライン引数はString型で渡されるため,StringからIntegerにパースしています.

動的タスクを生成する

スクリプトで動的にタスクを生成することも出来ます.

def items = ["apple", "orange", "banana"];

items.each {item ->
    task "$item" {
        doLast {
            println("This is task for $item.");
        }
    }
}

実行します.

% gradle apple -q
This is task for apple.

環境ごとに処理を変えるのに使えそうです.

Java プラグインを使う

Javaの開発で必要となる基本機能はJavaプラグインで提供されています.build.gradleに以下を追加することで利用可能です.
build.configに以下を追加します.

plugins {
    id 'java'
}

以下の書き方は現在はレガシーで推奨されていません.

apply plugin: 'java'

apply pluginはレガシーです。
https://docs.gradle.org/current/userguide/plugins.html#sec:old_plugin_applicationapply plugin

プラグインの利用はplugin DSLを利用します。

なんとなく使わないGradle | ログラス Productチーム アドベントカレンダー 2022

実行します.

% gradle java
BUILD SUCCESSFUL in 459ms
2 actionable tasks: 2 up-to-date

これでプロジェクトがコンパイルされ,jarファイルが生成されました.クラスファイルはbuild/classesフォルダ内に生成されます.build/libsフォルダ内にjarファイルが生成されます.

gradle javaはクラスファイルを生成し,それらをまとめてjarファイルを生成するという一連の処理を行うタスクです.

gradle buildとgradle javaの違い

  • gardle build
    • Java,Groovy,ScalaなどGradleがサポートしている.
  • gradle buildはサポートしている任意の言語のプロジェクトのビルドを行う.
  • gradle java
    • Javaプロジェクトのビルドを行う.
  • gradle groovy
    • Groovyプロジェクトのビルドを行う.

JavaやGroovyプラグインはその言語専用のタスクが用意されている

Javaプラグインのタスク

タスク説明
compileJavaソースをコンパイルしてbuild/classesに格納する.
processResourcesリソースファイルをbuild/resourcesにコピーする.
classescompileJavaとprocessResourcesを一緒にしたもの.
testテストの実行.ソースのコンパイル,テストに必要なリソースのコピーなどを実施後,JUnitによるテストを実行.
compileTestJava, processTestResources, testClassesそれぞれcompileJava, processResources, classesのテスト用.それぞれテストクラスのコンパイル,テスト用リソースのコピー,両者を一緒に実行します.
jarコンパイルしてリソースファイルなどを準備した後にjarファイルを作成.Executable Jarを作成するわけではない
javadocソースを解析しjavadocを生成する.build/docs/javadoc内に生成する.
cleanビルドによって生成されたファイルをすべて消去する.

Javaプラグインのタスクを利用する

build.gradleに以下を追加します.

task createJar(dependsOn: [compileJava, jar]) {
    doLast {
        println("compiled and jar is created.");
    }
}

実行します.

% gradle createJar
> Task :createJar
compiled and jar is created.
BUILD SUCCESSFUL in 580ms
4 actionable tasks: 2 executed, 2 up-to-date

createJar()の引数でdependsOn: [compileJava, jar]を指定することで,createJarが実行される前に指定した引数のタスクcompileJavajarすべてが実行されます.

そして,最後にdoLastで記述した内容が実行されます.

executeでタスクを直接実行する

以下に記載のあるタスクからタスクを呼び出す方法についてです。

[gradle 3.5] タスクからタスク呼び出し(※executeを使用) – Qiita

非推奨のようです.公式によると,dependenciesを使えるなら使ったほうが良いようです.

The truth is that we don’t officially support calling tasks programmatically. Instead you are supposed to use task dependencies whenever possible. That said, I think task.execute() should work, but as you mentioned it won’t execute dependent tasks.

Gradleでタスクから別のタスクを呼び出す – みちしるべ

tasks

タスクはtasksオブジェクトにまとめられています.

実行可能クラスの用意

src/main/java/org/exampleのMain.javaを以下のように修正.

package org.example;

public class Main {
    public static void main(String[] args) {
        Main main = new Main();
        main.printGreeting("Kenji");
        main.printGreeting("Hiroko");
    }

    public String greeting(String name) {
        return String.format("I am %s.", name);
    }

    public void printGreeting(String name) {
        System.out.println(this.greeting(name));
    }
}

applicationプラグインを追加

build.gradleに以下を追加

plugins {
    id 'java'
    id 'application'
}

application {
    mainClass = 'org.example.Main'
}

参考
The Application Plugin

実行します.

% gradle -q run
I am Kenji.
I am Hiroko.

gradle runは実行前にコンパイルしてくれます.

プログラムを実行するタスクを作成する

runを実行するタスクを作成します.build.gradleに以下を追加します.

task executeMain(dependsOn:[jar, run]) {
    doLast {
        println("Start execution");
    }
}

実行します.

% gradle executeMain
> Task :run
I am Kenji.
I am Hiroko.
> Task :executeMain
Start execution
BUILD SUCCESSFUL in 477ms
5 actionable tasks: 3 executed, 2 up-to-date

Intellij IDEAから実行する

Run/Debug Configurationに以下のように追加します.

このConfigurationが選択されている状態でIntellij IDEAのRunボタンをクリックすればgradle executeMainが実行されます.

UnitTest

MainTestクラスの作成

package org.example;

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

public class MainTest {
    @Test
    public void testMain() {
        String name = "Satoshi";
        Main main = new Main();
        assertNotNull(main);
        assertEquals("I am Satoshi.", main.greeting(name));
    }
}

実行します.

% gradle test
BUILD SUCCESSFUL in 4s
4 actionable tasks: 4 executed

テストレポート

テスト実行後はテストレポートが作成されます.build/reports/tests/test配下に作成されます.

index.htmlを開きます.以下のようにテストレポートが作成されます.

よかったらシェアしてね!
目次