【入門】Gradle とは? Maven リポジトリで Dependencies を解決

スポンサーリンク

対象者

  • Gradle って何?
  • Groovy DSL の書き方
  • Gradle のサンプルコードが欲しい
  • Gradle の公式ドキュメントを読む前に概要を知りたい

わかりやすさ重視で記載しているので、厳密な定義は公式ドキュメントを読んでください。

なお、本記事は以下の Java 入門用の記事の初回です。他の記事は以下をご覧ください。

スポンサーリンク

Gradle とは?代表的な2つの使い方

Gradle とは Java のビルドツールです。Gradle では、主に以下の2つのビルド作業を自動化します。

また、Gradle の設定ファイルを配布するだけで、他のコンピュータでも同じビルド環境を作成できます。

使い方1:任意のビルド作業を自動実行

Gradle では Task と呼ばれる単位で任意のビルド作業を実行できます。 Task の一例は以下のとおりです。

何が嬉しいか

大量のオプションがついたビルドコマンドやテストコードを毎回、手動で入力する作業から開放されます。

使い方2:モジュールの依存関係を自動解決

モジュール依存関係とは、「モジュール A を実行するために他のモジュールが必要な状態」のことを表します。

Gradle では、モジュール A をインストールする際に、依存関係にある他のモジュールも自動でインストールし、依存関係を解決してくれます。(例:依存関係のあるモジュールを取得

何が嬉しいか

依存関係にあるモジュールを1つ1つ調べて、手動でインストールする作業から開放されます。

スポンサーリンク

Gradle のインストール方法

SDKMAN!(パッケージ管理ソフト)を使用して Gradle 6.6.1 をインストールします。

  1. SDKMAN! をインストール(既にインストールされている場合はスキップ)
    curl -s "https://get.sdkman.io" | bash
    source "$HOME/.sdkman/bin/sdkman-init.sh"

    以下のコマンドでバージョンが表示されるとインストール成功

    sdk version
    $ sdk version
    ==== BROADCAST =================================================================
    * 2020-09-21: micronaut 2.0.3 now available for download.
    * 2020-09-21: jbang 0.47.1 now available for download.
    * 2020-09-20: jbang 0.46.1 @jbangdev https://git.io/JUEb5
    ================================================================================
    
    SDKMAN 5.9.0+555
  2. JDK バージョン 8 以上をインストール(既にインストールされている場合はスキップ)
    sdk install java

    以下のコマンドで JDK バージョン 8 以上が表示されるとインストール成功

    java -version
    $ java -version
    openjdk version "11.0.8" 2020-07-14
    OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.8+10)
    OpenJDK 64-Bit Server VM AdoptOpenJDK (build 11.0.8+10, mixed mode)
  3. Gradle をインストール
    sdk install gradle

    以下のコマンドでバージョンが表示されるとインストール成功

    gradle -version
    $ gradle -version
    ------------------------------------------------------------ Gradle 6.6.1 ------------------------------------------------------------ Build time: 2020-08-25 16:29:12 UTC Revision: f2d1fb54a951d8b11d25748e4711bec8d128d7e3 Kotlin: 1.3.72 Groovy: 2.5.12 Ant: Apache Ant(TM) version 1.10.8 compiled on May 10 2020 JVM: 11.0.8 (AdoptOpenJDK 11.0.8+10) OS: Linux 4.14.193-149.317.amzn2.x86_64 amd64

補足

SDKMAN! で利用可能なソフトウェアは以下のドキュメントに記載されたソフトウェアだけです。Maven セントラルリポジトリなどから、依存関係を解決しながらモジュールをインストールする場合は、Gradle を利用する必要があります。

Available SDKs - SDKMAN! the Software Development Kit Manager
SDKMAN! is a tool for managing parallel versions of multiple Software Development Kits on most Unix based systems.

Gradle の6つの書き方

Gradle では、Groovy DSL もしくは Kotlin DSL を利用して、ビルドを自動化するビルドスクリプト(build.gradle)を記載します。

今回紹介する Groovy DSL では、主に以下の6つの書式を持ちます。

書き方1: Properties(変数)

Properties は、オブジェクトの持つ変数のことです。

Gradle がデフォルトで利用可能な Project オブジェクトの Properties 一覧は以下のとおりです。

Project - Gradle DSL Version 8.5

書き方:Properties

Properties の書き方は以下のとおりです。

<obj>.<name>
<obj>.<name> = <value>
"$<name>"
"${<obj>.<name>}"

例:Properties を操作する

ビルドスクリプト(build.gradle)で、ビルドディレクトリを格納する Property である "buildDir" を操作してみます。

vim build.gradle
println project.buildDir // property の値を取得

project.buildDir = "test" // property に値をセット
println project.buildDir

println "buildDirの値は $buildDir です。" //文字列に property の値を埋め込みます
println "buildDirの値は ${project.buildDir} です。" //文字列に property の値を埋め込みます

補足

デフォルトのオブジェクトである Project オブジェクトは省略可能です。そのため以下のような記載方法が可能です。

println buildDir // property の値を取得

Property の操作結果

gradle --configure-on-demand コマンドで結果を確認してみましょう。

gradle --configure-on-demand
$ gradle --configure-on-demand

Configuration on demand is an incubating feature.

Configure project :
/home/ec2-user/build
/home/ec2-user/test
buildDirの値は /home/ec2-user/test です。
buildDirの値は /home/ec2-user/test です。

結果は Configure project : に表示されます。

書き方2: Methods(メソッド)

Methods は、オブジェクトが所有する関数のことです。

Gradle がデフォルトで利用可能な Project オブジェクトの Methods 一覧は以下のとおりです。

Project - Gradle DSL Version 8.5

書き方: Methods

Methods の書式は以下のとおりです。

<obj>.<name>()
<obj>.<name>(<arg>,<arg>)
<obj>.<name> <arg>,<arg>

例:Methods を呼び出す

ディレクトリを作成する "mkdir()" Method を使用してみます。

vim build.gradle
mkdir("src/main/java") //ディレクトリ src/main/java を作成します。

mkdir() Method の実行結果

gradle --configure-on-demand コマンドでメソッドを実行してみましょう。

ls
build.gradle
gradle --configure-on-demand
ls
build.gradle src

書き方3: Script blocks (スクリプト)

Script blocks はメソッドとほぼ同じ機能です。メソッドとの違いは公式ドキュメントに記載があります。

Blocks are also methods, just with specific types for the last argument.

There are two important aspects of blocks that you should understand:

1. They are implemented as methods with specific signatures.
2. They can change the target ("delegate") of unqualified methods and properties.

https://docs.gradle.org/current/userguide/groovy_build_script_primer.html#groovy:blocks

Gradle がデフォルトで利用可能な Project オブジェクトの Script blocks 一覧は以下のとおりです。

Project - Gradle DSL Version 8.5

なお、上記の公式ドキュメントには Script blocks と Blocks の用語が混在しています。同じ意味で使っていると思うのですが。。。

書き方: Script blocks

Script blocks を利用するための書式は以下のとおりです。

<obj>.<name> { 
     ...
}
<obj>.<name>(<arg>,<arg>){
     ...
}

具体的なビルドスクリプトの書き方は後述する Tasks, Plugins, Dependencies で記載します。現時点では "{ }"で囲む書式があるんだな。ぐらいの認識でOKです。

書き方4: Tasks (任意の Task)

Tasks は、ビルドの作業内容のことです。

Tasks オブジェクト が持つ PropertiesMethods は以下のとおりです。

Task - Gradle DSL Version 8.5

書き方: Tasks

Tasks の書き方は以下のとおりです。

task <Task名>
task <Task名> { configure closure }
task <Task名>(type: SomeType)
task <Task名>(type: SomeType) { configure closure }

例:Hello World! の Task を作成する

Gradle では任意の Task を作成可能です。ここでは例として Hello World! Task を作成します。

vim build.gradle
task task1 {
        println "Hello world!"
}

gradle <Task名> コマンドで Task を実行してみましょう。

gradle task1
$ gradle task1

Configure project :
Hello world!

BUILD SUCCESSFUL in 1s

Configure project : に Hello world! が表示されることが確認できます。

例:Task 一覧を確認

Task 一覧を表示するためには gradle task コマンドを利用します。

gradle tasks
Build Setup tasks
-----------------
init - Initializes a new Gradle build.
wrapper - Generates Gradle wrapper files.

Help tasks
----------
(中略)
properties - Displays the properties of root project 'ec2-user'.
tasks - Displays the tasks runnable from root project 'ec2-user'.

先程作成した "task1" が Task 一覧に無いので、登録しましょう

例:独自のTask を Task 一覧に追加

Task 一覧に独自の Task を追加するには2つの Properties ["group", "description"]を使用します。

vim build.gradle
task task1 {
        group = "Custom" //group property を設定します。task のオブジェクト名は省略します。
        description = "Hello world を表示します。" //task の説明を記載します。
        println "Hello world!"
}

task task2(group: "Custom2", description: "Hello world を表示します。") { //引数で指定することも可能です。 
        println "Hello world!"
}

もう一度 Task 一覧を確認してみましょう。

gradle tasks
Build Setup tasks
-----------------
init - Initializes a new Gradle build.
wrapper - Generates Gradle wrapper files.

Custom tasks
------------
task1 - Hello world を表示します。

Custom2 tasks
-------------
task2 - Hello world を表示します。

Help tasks
----------
(中略)
properties - Displays the properties of root project 'ec2-user'.
tasks - Displays the tasks runnable from root project 'ec2-user'.

無事、作成した Task が Task 一覧に表示されることを確認できました。

例:Task を指定した時だけ実行

現在、gradle tasks コマンドを実行した際に task1, task2 が実行されています。

gradle tasks
> Configure project :
Hello world!
Hello world!

そこで、Task オブジェクトの "doLast" Method を利用することで、Task 名を指定された時だけ、Task を実行するようにします。

vim build.gradle
task task1 {
        group = "Custom" //group property を設定します。task のオブジェクト名は省略します。
        description = "Hello world を表示します。" //task の説明を記載します。
        doLast{
                println "Hello world!"
        }
}

task task2(group: "Custom2", description: "Hello world を表示します。") { //引数で指定することも可能です。 
        doLast{
                println "Hello world!"
        }
}

doLast() Method の結果を確認

gradle tasks

Task 名を指定すると、指定した Task だけが動作します。

gradle task1
$gradle task1

> Task :task1
Hello world!

BUILD SUCCESSFUL in 690ms
1 actionable task: 1 executed

書き方5: Plugins(既製の Task を追加)

Plugins は、誰かが作った project を追加する機能です。

Core Plugins 一覧は以下のとおりです。

Gradle Plugin Reference

Non-core Plugins 一覧は以下のページから検索可能です。

Gradle - Plugins

書き方: Plugins

Plugins の書式は以下の2種類があります。

apply plugin: '<プラグイン名>'
plugins{
     id "<プラグイン名1>"
     id "<プラグイン名2>"
}

例:ビルドを実行する(java Plugin)

"Java" Plugin の "build" Task を追加し、ビルドを実行します。なお、ソースコードは src/main/java 配下に置きます。

事前準備(ビルド用のソースコード)

  1. mkdir -p src/main/java
  2. vim src/main/java/HelloWorld.java
    public class HelloWorld {
            public static void main(String[] args){
                    System.out.println("Hello world.");
            }
    }

java Plugin でビルド用の Task を追加、およびビルドを実行

  1. vim build.gradle
    apply plugin: 'java'
  2. gradle tasks
    > Task :tasks
    
    ------------------------------------------------------------
    Tasks runnable from root project
    ------------------------------------------------------------
    
    Build tasks
    -----------
    assemble - Assembles the outputs of this project.
    build - Assembles and tests this project.
    buildDependents - Assembles and tests this project and all projects that depend on it.
    buildNeeded - Assembles and tests this project and all projects it depends on.
    classes - Assembles main classes.
    clean - Deletes the build directory.
    jar - Assembles a jar archive containing the main classes.
    testClasses - Assembles test classes.
    
  3. gradle build
    $gradle build BUILD SUCCESSFUL in 1s 2 actionable tasks: 2 executed
  4. ls build/classes/java/main/HelloWorld.class
    $ ls build/classes/java/main/HelloWorld.class
    build/classes/java/main/HelloWorld.class

例:プログラムを実行する(application Plugin)

事前の準備としてこちらのソースコードを用意してください

  1. vim build.gradle
    plugins {
        id 'application'
    }
    
    mainClassName = 'HelloWorld'
  2. gradle run
    $ gradle run
    > Task :run
    Hello world.
    
    BUILD SUCCESSFUL in 839ms
    2 actionable tasks: 2 executed

書き方6: Dependencies(依存関係の解決)

Dependencies は、モジュール依存関係を解決する機能です。

Dependencies オブジェクトの持つ Properties, Methods は以下のとおりです。

DependencyHandler - Gradle DSL Version 8.5

書き方: Dependencies

Dependencies の書式は以下のとおりです。

dependencies {
    <configurationName> '<グループID>:<アーティファクトID>:<バージョン>'
}
dependencies {
    <configurationName> group:'<グループID>',name:'<アーティファクトID>version':<バージョン>'
}

<configurationName> の例

https://docs.gradle.org/current/userguide/java_plugin.html#sec:java_plugin_and_dependency_management

例:Maven リポジトリからモジュールを取得

Gradle を用いて org.apache.commons.lang3.StringUtils モジュールを取得するデモを実施します。まずはデモ用のプログラム src/main/java/Dependencies.java を作成します。

事前準備

vim src/main/java/Dependencies.java
import org.apache.commons.lang3.StringUtils;

public class Dependencies {
        public static void main(String[] args) {
                String str="Hello";
                System.out.println("変数 str に文字が入っている場合 false -->:" + StringUtils.isEmpty(str));
        }
}

Dependencies を利用しない場合(失敗例)

vim build.gradle
plugins {
    id 'application'
}

mainClassName = 'Dependencies'

Dependencies を使用しない状態でプログラムを実行してみます。

gradle run
> Task :compileJava FAILED
/Users/hogetech/work/test/src/main/java/Dependencies.java:1: エラー: パッケージorg.apache.commons.lang3は存在しません

org.apache.commons.lang3.StringUtils モジュールが無いと怒られます。

Dependencies を利用する場合(成功例)

次に Dependencies を利用して、Maven リポジトリから org.apache.commons.lang3 モジュールを取得します。

vim build.gradle
plugins {
    id 'application'
}

mainClassName = 'Dependencies'

repositories {
    mavenCentral()
}

dependencies {
    compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.11'
}

なお、Dependencies で指定するモジュールの GroupID, Name, Version は Maven リポジトリから検索可能です。

Just a moment...

Dependencies を指定したビルドスクリプトの実行結果

gradle run
> Task :run
変数 str に文字が入っている場合 false -->:false

モジュールが正しく import され、実行に成功したことがわかります。

例: 依存関係を解決していることを確認

複雑な依存関係を持つ kinesis モジュールを利用して、依存関係を解決していることを確認してみます。まずは、モジュールの GroupID, Name, Version は Maven リポジトリから検索します。

以下のどちらのサイトで検索してもOKです。

Just a moment...
Maven Central Repository Search
Official search by the maintainers of Maven Central Repository

検索の結果、取得するモジュールは以下のとおりであることがわかりました。

  • <グループID> = software.amazon.awssdk
  • <アーティファクトID> = kinesis
  • <バージョン> = 2.15.2

モジュールを取得する Gradle Task を作成

依存関係を可視化するために、依存関係を解決するために利用するモジュールをローカルにダウンロードするタスクを作成します。

vim build.gradle
apply plugin: 'java' //compileOnly を利用するため

//リポジトリの設定
repositories {
    mavenCentral() //https://repo.maven.apache.org/maven2/ から取得
}

//リポジトリから取得するモジュールの設定
dependencies {
    compileOnly "software.amazon.awssdk:kinesis:2.15.2"
}

//jar ディレクトリを削除
task delDependJar {
    delete 'jar'
}

// 依存するモジュールを jar ディレクトリにコピーする
task getModule(dependsOn: delDependJar) {
    group = "Hoge"
    description = "依存関係の解決" 
    
    doLast {
        configurations.compileOnly.each {
            def fromJarFile = it.absolutePath
            copy {
                from fromJarFile
                into 'jar'
            }   
        }   
    }   
}

依存関係を解決したモジュールを確認する

gradle getModule
ls jar/
annotations-2.15.2.jar						netty-codec-4.1.46.Final.jar
apache-client-2.15.2.jar					netty-codec-http-4.1.46.Final.jar
auth-2.15.2.jar							netty-codec-http2-4.1.46.Final.jar
aws-cbor-protocol-2.15.2.jar					netty-common-4.1.46.Final.jar
aws-core-2.15.2.jar						netty-handler-4.1.46.Final.jar
aws-json-protocol-2.15.2.jar					netty-nio-client-2.15.2.jar
commons-codec-1.11.jar						netty-reactive-streams-2.0.4.jar
commons-logging-1.2.jar						netty-reactive-streams-http-2.0.4.jar
eventstream-1.0.1.jar						netty-resolver-4.1.46.Final.jar
http-client-spi-2.15.2.jar					netty-transport-4.1.46.Final.jar
httpclient-4.5.9.jar						netty-transport-native-epoll-4.1.46.Final-linux-x86_64.jar
httpcore-4.4.11.jar						netty-transport-native-unix-common-4.1.46.Final.jar
jackson-annotations-2.10.4.jar					profiles-2.15.2.jar
jackson-core-2.10.4.jar						protocol-core-2.15.2.jar
jackson-databind-2.10.4.jar					reactive-streams-1.0.3.jar
jackson-dataformat-cbor-2.10.4.jar				regions-2.15.2.jar
kinesis-2.15.2.jar						sdk-core-2.15.2.jar
metrics-spi-2.15.2.jar						slf4j-api-1.7.28.jar
netty-buffer-4.1.46.Final.jar					utils-2.15.2.jar

kinesis-2.15.2.jar を利用するために、依存関係にあるモジュールを取得していることがわかります。

例: 独自の Maven リポジトリの指定

vim build.gradle
repositories {
    maven {
        url 'http://redshift-maven-repository.s3-website-us-east-1.amazonaws.com/release'
    }   
}

MavenArtifactRepository maven(Closure closure) で url Properties を指定します。

RepositoryHandler - Gradle DSL Version 8.5
MavenArtifactRepository - Gradle DSL Version 8.5

例: BOM の利用

BOM ファイルは複数のモジュールのバージョン一覧を記載したファイルです。

複数のモジュールをインストールする場合、依存関係がバッティングする場合があります。

この場合、モジュール C はどのバージョンを入れればいいの?という話になります。

これを解決するのが BOM ファイルと呼ばれるものです。以下のサイトにわかりやすい説明があります。

BOMプロジェクトとは - Qiita
BOMプロジェクトについて調べたことまとめ。参考:…

BOM を利用する場合のビルドスクリプトの書き方の例を掲載します。

vim build.gradle
apply plugin: 'java'
  
repositories {
    mavenCentral()
}

dependencies {
        compileOnly 'software.amazon.awssdk:kinesis:2.1.4'
        compileOnly 'software.amazon.awssdk:s3:2.1.4'
}
apply plugin: 'java'
  
repositories {
    mavenCentral()
}

dependencies {
  compileOnly platform('software.amazon.awssdk:bom:2.1.4')
  compileOnly 'software.amazon.awssdk:kinesis'
  compileOnly 'software.amazon.awssdk:s3'
}

BOM を利用した場合、BOM にモジュールのバージョンが記載されているため、モジュールにバージョンを記載する必要が無いです。BOM ファイル software.amazon.awssdk:bom:2.1.4 の内容は下記のページを参照してください。

Maven Central Repository Search
Official search by the maintainers of Maven Central Repository

個人的によく使う設定

気が向いたら追記していきます。

plugins {
    id 'application'
}

mainClassName = '<パッケージ名>.<main クラス名>'

run {
    if (project.hasProperty('args')) {    // "args" というプロパティが渡されていたら
        args project.args.split('\\s+')   // 空白文字で split して、 run タスクの args オプションにセットする
    }
    standardInput = System.in
}

repositories {
    mavenCentral()
}

dependencies {
	implementation platform('<bom>')
	implementation '<モジュール>'
	implementation 'org.slf4j:slf4j-log4j12:1.7.21' //log4j.properties の設定も忘れずに
}
plugins {
    id 'application'
}

mainClassName = 'KinesisClient.Library'

run {
    if (project.hasProperty('args')) {    // "args" というプロパティが渡されていたら
        args project.args.split('\\s+')   // 空白文字で split して、 run タスクの args オプションにセットする
    }
}
plugins {
    id 'application'
}

mainClassName = 'KinesisClient.Library'

run {
    standardInput = System.in //標準入力(端末)から入力を受け付けます
}

参考文献

# 公式ドキュメント ユーザーガイド

Gradle User Manual

#公式ドキュメント DSL Reference

Gradle DSL Version 8.5

#公式ドキュメントの日本語訳

Gradle DSL Version 2.2-20140924021627+0000