こんにちは!
AWSサーバーレスのプロジェクトで、最近では Java を採用する事例も少しずつ増えてきました。従来のサーバーレスでの Java 開発にはコールドスタート問題がよく聞かれましたが、最近は Lambda のSnapStart機能を使用することでコールドスタートを軽減することができます。Java の開発効率の高さとサーバーレスを掛け算は私たちも最近愛用しています。
私たちは通常、Java 開発で、Java を gradle でビルドし Lambda へアップロードしますが、maven に慣れている人にとってgradleは少々とっつきにくい面があるかもしれません。
本記事では、gradle を使用した Java のビルド方法から、初心者向けに gradle をわかりやすく解説します。
gradle は maven の後発のため Maven を拡張・改良したモジュールと言えます。結論これから始めるプロジェクトであれば圧倒的に gradle を推奨します。例えば以下の点において gradle が優れていると言えます。
ビルドタスクを Kotlin のDSLベースで作成が可能となっており優れた開発者体験を提供してくれます。そのためビルドのプロセス定義の作業にIDEやエディターのサポートの恩恵を受けることができます。
Gradle 8.4
となります。
$ gradle -v
------------------------------------------------------------
Gradle 8.4
------------------------------------------------------------
Kotlin: 1.9.10
Groovy: 3.0.17
Ant: Apache Ant(TM) version 1.10.13 compiled on January 4 2023
JVM: 21.0.1 (Homebrew 21.0.1)
OS: Mac OS X 13.5.2 x86_64
まずはじめに、gradle をOSXへインストールします。
その他JDKインストールなど当然必要なので、詳しくは公式サイト見ておきましょう。
$ brew install gradle
$ gradle -v
------------------------------------------------------------
Gradle 8.4
------------------------------------------------------------
Kotlin: 1.9.10
Groovy: 3.0.17
Ant: Apache Ant(TM) version 1.10.13 compiled on January 4 2023
JVM: 21.0.1 (Homebrew 21.0.1)
OS: Mac OS X 13.5.2 x86_64
細かいところはお好みでインストールしましょう。
$ gradle init
Select type of project to generate:
1: basic
2: application
3: library
4: Gradle plugin
Enter selection (default: basic) [1..4] 2
Select implementation language:
1: C++
2: Groovy
3: Java
4: Kotlin
5: Scala
6: Swift
Enter selection (default: Java) [1..6] 3
Generate multiple subprojects for application? (default: no) [yes, no] no
Select build script DSL:
1: Kotlin
2: Groovy
Enter selection (default: Kotlin) [1..2] 1
Select test framework:
1: JUnit 4
2: TestNG
3: Spock
4: JUnit Jupiter
Enter selection (default: JUnit Jupiter) [1..4] 4
Project name (default: tutorial): gradle
Source package (default: tutorial): com.gradle.gradle
Enter target version of Java (min. 7) (default: 17): 17
Generate build using new APIs and behavior (some features may change in the next minor release)? (default: no) [yes, no] no
インストール後は、プロジェクトのルートディレクトリに出力された gradlew というファイルを実行することで、プロジェクトのチームメンバーが gradle をインストールせずに、gradle を実行することが可能となります。
$ bash ./gradlew [command]
コトリン形式でタスクを登録できます。Javascript の npm でいうところの package.json 内の scripts みたいなものですね。(scripts よりもリッチなことができる)
ルートプロジェクト及びサブプロジェクトのタスクを一覧で表示します。
$ bash gradlew tasks --all
サブプロジェクトのbuild.gradle.kts
へ以下を入力すると、タスクとして実行が可能です。
tasks.register("hello") {
println("Hello!")
}
tasks.register("greet") {
println("How are you?")
dependsOn("hello")
}
$ bash gradlew app:greet
How are you?
Hello!
タスク作成方法のさらなる詳しい情報は、コトリンの DSL の公式ドキュメントを見ましょう。
Kotlin DSL公式サイト
結構充実しています。
gradle で jar を生成します。
$ bash gradlew build
> Task :app:compileJava
> Task :app:processResources
> Task :app:classes
> Task :app:jar
> Task :app:startScripts
> Task :app:distTar
> Task :app:distZip
> Task :app:assemble
> Task :app:compileTestJava
> Task :app:processTestResources
> Task :app:testClasses
> Task :app:test
> Task :app:check
> Task :app:build
build コマンドでは、アセンブル〜テストを自動的に一式行ってくれます。
もちろん、前述のタスクの登録を応用し好みのスクリプトを追加することも可能です。
gradle の特徴にビルドのプロセスを独自にスクリプトで拡張できる点があります。柔軟なビルドプロセスを定義できるので、CICD との連携も視野に入れて柔軟なバックエンド開発環境が構築可能ですね。
jar ファイルは以下のディレクトリに出力されます。{sub project name}/build/libs/app.jar
そして、gradle では単純に jar ファイルの出力のみを行うコマンドも搭載しています。
$ bash gradlew jar
# または
$ bash gradlew assemble
一方で、実際のCICDでのビルドは bash gradlew build
を使用しましょう。以下はビルドに関連するコマンドのまとめです。
タスク | 説明 |
assemble | コンパイルを実行しJAR、WAR、ZIP、TARファイル等々を生成 |
build | assemble 後にテストを実行 |
buildDependents | プロジェクトが依存するプロジェクトを含め build を実行 |
buildNeeded | 指定プロジェクトだけでなく、そのプロジェクトの testRuntime 依存関係に設定されているプロジェクトをすべてテスト |
classes | メインクラスを assemble |
clean | 成果物(build ディレクトリ配下)を削除 |
jar | メインクラスを含む Jar ファイルを生成 |
testClasses | テストクラスを assemble |
サブプロジェクトの Java の実行は以下のコマンドで可能です。
$ bash gradlew run
上記のコマンドでは、{sub project name}/src/main/java/gradle/App.java
が実行されます。
public class App {
public String getGreeting() {
return "Hello World!";
}
public static void main(String[] args) {
System.out.println(new App().getGreeting());
}
}
gradle でのパッケージで抑えるべき基本は、リポジトリと依存関係の指定をどこで行っているかです。サブプロジェクトの gradle.build.kts
を見てみましょう。
repositories {
mavenCentral()
}
dependencies {
testImplementation("junit:junit:4.13.2")
implementation("com.google.guava:guava:32.1.2-jre")
}
repositories
にはパッケージ取得先のリポジトリを指定し、dependencies
には依存関係(使用するパッケージ)を指定します。
上記の設定はデフォルトの設定ですが、まずリポジトリには Java のデファクトスタンダードのMavenを指定しています。つまり、gradle のプロジェクトにおいては、Maven のパッケージを制限なく利用できるということです。repositories
の設定は基本的に変更しませんが、リポジトリを独自運用していたりする場合は、適宜変更します。(大手企業で社内で開発資産を蓄積しているようなケース)
そして repositories
にはパッケージを指定しますが、前述の設定例では Java のテストモジュールとしてデファクトスタンダードな JUnit がインストールされています。依存関係の構文は以下の通りです。
com.google.guava:guava:32.1.2-jre | junit:junit:4.13.2 | ||
グループ | com.google.guava | junit | |
名称 | guava | junit | |
バージョン | 32.1.2-jre | 4.13.2 |
gradle を使用して依存関係を可視化してみましょう。インストールしたパッケージが依存しているパッケージがツリーになって表示されます。
$ bash gradlew app:dependencies
> Task :app:dependencies
------------------------------------------------------------
Project ':app'
------------------------------------------------------------
annotationProcessor - Annotation processors and their dependencies for source set 'main'.
No dependencies
compileClasspath - Compile classpath for source set 'main'.
\--- com.google.guava:guava:32.1.1-jre
+--- com.google.guava:guava-parent:32.1.1-jre
| +--- com.google.code.findbugs:jsr305:3.0.2 (c)
| +--- org.checkerframework:checker-qual:3.33.0 (c)
| +--- com.google.errorprone:error_prone_annotations:2.18.0 (c)
| \--- com.google.j2objc:j2objc-annotations:2.8 (c)
+--- com.google.guava:failureaccess:1.0.1
+--- com.google.code.findbugs:jsr305 -> 3.0.2
+--- org.checkerframework:checker-qual -> 3.33.0
+--- com.google.errorprone:error_prone_annotations -> 2.18.0
\--- com.google.j2objc:j2objc-annotations -> 2.8
compileOnly - Compile-only dependencies for the 'main' feature. (n)
No dependencies
default - Configuration for default artifacts. (n)
No dependencies
implementation - Implementation dependencies for the 'main' feature. (n)
\--- com.google.guava:guava:32.1.1-jre (n)
mainSourceElements - List of source directories contained in the Main SourceSet. (n)
No dependencies
runtimeClasspath - Runtime classpath of source set 'main'.
\--- com.google.guava:guava:32.1.1-jre
+--- com.google.guava:guava-parent:32.1.1-jre
| +--- com.google.code.findbugs:jsr305:3.0.2 (c)
| +--- org.checkerframework:checker-qual:3.33.0 (c)
| \--- com.google.errorprone:error_prone_annotations:2.18.0 (c)
+--- com.google.guava:failureaccess:1.0.1
+--- com.google.code.findbugs:jsr305 -> 3.0.2
+--- org.checkerframework:checker-qual -> 3.33.0
\--- com.google.errorprone:error_prone_annotations -> 2.18.0
runtimeElements - Runtime elements for the 'main' feature. (n)
No dependencies
runtimeOnly - Runtime-only dependencies for the 'main' feature. (n)
No dependencies
testAnnotationProcessor - Annotation processors and their dependencies for source set 'test'.
No dependencies
testCompileClasspath - Compile classpath for source set 'test'.
+--- com.google.guava:guava:32.1.1-jre
| +--- com.google.guava:guava-parent:32.1.1-jre
| | +--- com.google.code.findbugs:jsr305:3.0.2 (c)
| | +--- org.checkerframework:checker-qual:3.33.0 (c)
| | +--- com.google.errorprone:error_prone_annotations:2.18.0 (c)
| | \--- com.google.j2objc:j2objc-annotations:2.8 (c)
| +--- com.google.guava:failureaccess:1.0.1
| +--- com.google.code.findbugs:jsr305 -> 3.0.2
| +--- org.checkerframework:checker-qual -> 3.33.0
| +--- com.google.errorprone:error_prone_annotations -> 2.18.0
| \--- com.google.j2objc:j2objc-annotations -> 2.8
\--- org.junit.jupiter:junit-jupiter:5.9.3
+--- org.junit:junit-bom:5.9.3
| +--- org.junit.jupiter:junit-jupiter:5.9.3 (c)
| +--- org.junit.jupiter:junit-jupiter-api:5.9.3 (c)
| +--- org.junit.jupiter:junit-jupiter-params:5.9.3 (c)
| \--- org.junit.platform:junit-platform-commons:1.9.3 (c)
+--- org.junit.jupiter:junit-jupiter-api:5.9.3
| +--- org.junit:junit-bom:5.9.3 (*)
| +--- org.opentest4j:opentest4j:1.2.0
| +--- org.junit.platform:junit-platform-commons:1.9.3
| | +--- org.junit:junit-bom:5.9.3 (*)
| | \--- org.apiguardian:apiguardian-api:1.1.2
| \--- org.apiguardian:apiguardian-api:1.1.2
\--- org.junit.jupiter:junit-jupiter-params:5.9.3
+--- org.junit:junit-bom:5.9.3 (*)
+--- org.junit.jupiter:junit-jupiter-api:5.9.3 (*)
\--- org.apiguardian:apiguardian-api:1.1.2
testCompileOnly - Compile only dependencies for source set 'test'. (n)
No dependencies
testImplementation - Implementation only dependencies for source set 'test'. (n)
\--- org.junit.jupiter:junit-jupiter:5.9.3 (n)
testRuntimeClasspath - Runtime classpath of source set 'test'.
+--- com.google.guava:guava:32.1.1-jre
| +--- com.google.guava:guava-parent:32.1.1-jre
| | +--- com.google.code.findbugs:jsr305:3.0.2 (c)
| | +--- org.checkerframework:checker-qual:3.33.0 (c)
| | \--- com.google.errorprone:error_prone_annotations:2.18.0 (c)
| +--- com.google.guava:failureaccess:1.0.1
| +--- com.google.code.findbugs:jsr305 -> 3.0.2
| +--- org.checkerframework:checker-qual -> 3.33.0
| \--- com.google.errorprone:error_prone_annotations -> 2.18.0
+--- org.junit.jupiter:junit-jupiter:5.9.3
| +--- org.junit:junit-bom:5.9.3
| | +--- org.junit.jupiter:junit-jupiter:5.9.3 (c)
| | +--- org.junit.jupiter:junit-jupiter-api:5.9.3 (c)
| | +--- org.junit.jupiter:junit-jupiter-engine:5.9.3 (c)
| | +--- org.junit.jupiter:junit-jupiter-params:5.9.3 (c)
| | +--- org.junit.platform:junit-platform-launcher:1.9.3 (c)
| | +--- org.junit.platform:junit-platform-commons:1.9.3 (c)
| | \--- org.junit.platform:junit-platform-engine:1.9.3 (c)
| +--- org.junit.jupiter:junit-jupiter-api:5.9.3
| | +--- org.junit:junit-bom:5.9.3 (*)
| | +--- org.opentest4j:opentest4j:1.2.0
| | \--- org.junit.platform:junit-platform-commons:1.9.3
| | \--- org.junit:junit-bom:5.9.3 (*)
| +--- org.junit.jupiter:junit-jupiter-params:5.9.3
| | +--- org.junit:junit-bom:5.9.3 (*)
| | \--- org.junit.jupiter:junit-jupiter-api:5.9.3 (*)
| \--- org.junit.jupiter:junit-jupiter-engine:5.9.3
| +--- org.junit:junit-bom:5.9.3 (*)
| +--- org.junit.platform:junit-platform-engine:1.9.3
| | +--- org.junit:junit-bom:5.9.3 (*)
| | +--- org.opentest4j:opentest4j:1.2.0
| | \--- org.junit.platform:junit-platform-commons:1.9.3 (*)
| \--- org.junit.jupiter:junit-jupiter-api:5.9.3 (*)
\--- org.junit.platform:junit-platform-launcher -> 1.9.3
+--- org.junit:junit-bom:5.9.3 (*)
\--- org.junit.platform:junit-platform-engine:1.9.3 (*)
testRuntimeOnly - Runtime only dependencies for source set 'test'. (n)
\--- org.junit.platform:junit-platform-launcher (n)
(c) - A dependency constraint, not a dependency. The dependency affected by the constraint occurs elsewhere in the tree.
(*) - Indicates repeated occurrences of a transitive dependency subtree. Gradle expands transitive dependency subtrees only once per project; repeat occurrences only display the root of the subtree, followed by this annotation.
(n) - A dependency or dependency configuration that cannot be resolved.
A web-based, searchable dependency report is available by adding the --scan option.
全てのサブプロジェクトに同じバージョンのパッケージを適用したいケースがあるかと思います。例えば同じデータベースを参照するようなサブプロジェクト同士が、データベースへ通信を行うモジュールのバージョンをサブプロジェクトごとに定義するメリットは感じません。
まず gradle/libs.versions.toml
に以下を設定します。
[versions]
junitVer = "5.9.3"
guavaVer = "32.1.1-jre"
[libraries]
junit = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junitVer" }
guava = { module = "com.google.guava:guava", version.ref = "guavaVer" }
そしてサブプロジェクトの、build.gradle.kts
にgradle/libs.versions.toml
に設定したパッケージのバージョンを指定します。
dependencies {
// testImplementation("org.junit.jupiter:junit-jupiter:5.9.3")
testImplementation(libs.junit)
// implementation("com.google.guava:guava:32.1.1-jre")
implementation(libs.guava)
}
試しに、run コマンドで実行してみるときちんと動作することがわかります。
$ bash gradlew run
gradle の Scan という機能を用いることで、ビルドの内容(ソースコードや実行環境などの塊)を gradle の WEB にアップロードできます。アップロード後、ランダムな URL が生成されますのでチームメンバーなどへ共有が可能です。アップロード前に利用規約への同意が必要なこともあり、セキュリティには注意しましょう。(URL は後で削除できますので一時的にチームへトラブルシューティングのヘルプを出す際に役立ちます)
実行方法は簡単で、ビルドコマンドに--scan
というオプションをつけるだけです。
$ bash gradlew build --scan
WEB画面はこんな感じです。依存関係などの情報もしっかり可視化されます。
gradle では、タスクやモデル(Kotlin DSL)の拡張に、プラグインを適用できます。プラグインを使用することで、第三者が開発した開発資産を自分のプロジェクトに簡単に取り入れることが可能です。(たった1行追記するだけで追加が可能)プラグインでは実現できることは主に以下です。
よくあるユースケースとして、Java の開発資産が豊富に蓄積されている企業が、複数の開発プロジェクトに対して自社独自の規約やモジュール、タスクを適用する事が可能です。
自社内のLAN内に Maven リポジトリを作成し、そこからプラグインパッケージを開発チームへ提供すれば情報漏洩の危険性も薄いです。
それではプラグインの適用方法を見ていきましょう。以下は、build.gradle.kts
の抜粋です。
plugins {
application
}
gradle でプロジェクトの雛形を作成した場合、デフォルトでは上記の Java のアプリケーション開発で使用するプラグインが適用されています。
そして、ここにプラグインを一つ追加してみます。
plugins {
application
`maven-publish`
}
※ ダブルクオートで囲うと反応しないので注意!
maven-publish についてはこちらをご覧ください。(maven-publish の説明は本セクションの趣旨と外れますので割愛します)
上記の設定を行うと、VS-CODE か JetBrains 製品を利用していれば「ローカルの Maven リポジトリと同期しますか?」みたいな画面下部にメッセージが表示されます。同期を実行した後に、タスクの一覧を出力するとプラグインが提供するタスクが一覧に現れるはずです。(自動同期設定も可能なのでお使いのエディターでお試しください)
$ bash gradlew app:tasks
Publishing tasks
----------------
publish - Publishes all publications produced by this project.
publishToMavenLocal - Publishes all Maven publications produced by this project to the local Maven cache.
これで、基本的なプラグインの使い方は終わりです。尚、プラグイン取得先のリポジトリはデフォルトでは以下の設定で MavenCentral となっており、MavenCentral に公開されているものなら自由に使用することが可能です。
gradle と先ほどの maven-publish を使用して、ローカルの maven リポジトリへプラグインをアップロードします。ローカルの Maven リポジトリへプラグインをアップロードするメリットは以下です。
基本的には MavenCentral や社内のLAN上のリポジトリ等々をリポジトリに指定するケースが大半かと思いますが、gradle では以下の build.gradle.kts
に以下の設定を加えることでローカルリポジトリを参照することができます。
repositories {
mavenCentral()
mavenLocal() # ← 追加
}
そして、maven-publish パッケージの機能を用いて、ローカルにパッケージを公開します。以下の設定値を、build.gradle.kts
に設定してみましょう。
publishing {
publications {
create<MavenPublication>("maven") {
groupId = "org.hoge.sample"
artifactId = "library"
version = "1.1"
from(components["java"])
}
}
// パブリッシュ先のローカル以外に設定する場合は以下を設定(未指定の場合はデフォルトでローカルMavenリポジトリとなる)
repositories {
maven {
url '...'
}
}
}
上記の各設定値の説明は以下です。
プパパティ | 説明 |
groupId | パッケージのグループ |
artifactId | パッケージの識別子(名称) |
version | パッケージのバージョン |
そして、タスク一覧を表示してみます。
$ bash gradlew app:tasks
Publishing tasks
----------------
generateMetadataFileForMavenPublication - Generates the Gradle metadata file for publication 'maven'.
generatePomFileForMavenPublication - Generates the Maven POM file for publication 'maven'.
publish - Publishes all publications produced by this project.
publishMavenPublicationToMavenLocal - Publishes Maven publication 'maven' to the local Maven repository.
publishToMavenLocal - Publishes all Maven publications produced by this project to the local Maven cache.
設定前後でいくつかタスクが追加されていると思います。これは先ほど設定したカスタム構成の結果です。各プラグインは Maven リポジトリに設定値のサンプルや設定できる項目を公開していますので、プラグインを使用する際は必ず一度目を通しましょう。
前述の maven-publish を使用して、ローカル Maven リポジトリへライブラリーをアップロードします。
前述のプラグインはリポジトリの定義がありませんおで、を使用するには、publishToMavenLocal
を実行し、ローカルMaven リポジトリへプラグインをインストールします。
$ bash gradlew publishToMavenLocal
上記のコマンドにより、ローカルの Maven リポジトリへアップロードされます。そして、build.gradle.kts
内のプロジェクトのリポジトリストに忘れずにローカルの Maven を追加しておきましょう。
repositories {
mavenCentral()
mavenLocal() // ←ローカルのMavenを指定
}
このローカルの Maven リポジトリのテクニックを応用することで、例えば Scala などで実装されたプロジェクトの機能をローカルで共有し合うことが可能です。(最終的に jar 形式であれば容易に Java プロジェクトに設定できる)
gradle は、ビルドを高速化する仕組みとしてインクリメントビルドを搭載しています。
インクリメンタルビルドとは、前回のビルドから入力が変化していないタスクの実行を行スキップする機能です。ビルド時に、Gradle は入力や出力が変更されたかどうかを判断します。もし変更されていれば、Gradle はタスクを実行し、そうでなければ実行をスキップします。
具体的にどのような挙動をしているのか実際にビルドコマンドを実行して見ていきましょう。
まず初めに、ビルドの詳細を確認したいのでプロジェクトのルートに gradle.properties
を実行し、ビルドの詳細出力モードを有効化します。
$ vim gradle.properties
org.gradle.console=verbose
そしてビルドを実行します。
$ bash gradlew app:build
> Task :app:compileJava UP-TO-DATE
> Task :app:processResources NO-SOURCE
> Task :app:classes UP-TO-DATE
> Task :app:jar UP-TO-DATE
> Task :app:startScripts UP-TO-DATE
> Task :app:distTar UP-TO-DATE
> Task :app:distZip UP-TO-DATE
> Task :app:assemble UP-TO-DATE
> Task :app:compileTestJava UP-TO-DATE
> Task :app:processTestResources NO-SOURCE
> Task :app:testClasses UP-TO-DATE
> Task :app:test UP-TO-DATE
> Task :app:check UP-TO-DATE
> Task :app:build UP-TO-DATE
各タスク毎に UP-TO-DATE というラベルが付与されているのかわかります。これは、入出力に変化がなかったためスキップされた(インクリメントビルド機能)、という事です。gradle には、以下のようなラベルの種類が存在します。
ラベル | 説明 |
---|---|
UP-TO-DATE | 変更のないタスク(実行をスキップ) |
SKIPPED | タスク実行が明示的に禁止されている状態 |
FROM-CACHE | タスク出力をビルドキャッシュ(キャッシュ機能)内の以前のビルドからローカルディレクトリにコピー |
NO-SOURCE | 必要な入力が渡されなかった為、タスク実行をスキップ |
インクリメンタルビルドは、すでに意味のないタスク(入出力に変化のないタスク)の実行を回避するのに役立つ優れてます。つまり、 開発者が1つのファイルに継続的に変更を加えている場合、プロジェクト内の他のファイルをすべてリビルドする必要はないという事です。
しかし、同じ開発者が先週作成された新しいブランチに切り替えるとどうなるでしょうか。 単純に考えれば、開発者はブランチの変化により、既にビルド済みのソースコードを再ビルドしなければいけない状況になると思います。(差分ビルドではなく完全ビルド)
そこで役立つのが gradle のビルドキャッシュ機能です。キャッシュは以前のビルド結果を保存し、ローカルでビルド済みのものを再構築するのを防いでくれます。
ではまず、ローカルビルドキャッシュを有効にしましょう。
$ vim gradle.properties
org.gradle.caching=true
そしてビルドタスクを実行し、キャッシュにデータを溜めます。
$ bash gradlew :app:clean :app:build
> Task :app:clean
> Task :app:compileJava
> Task :app:processResources NO-SOURCE
> Task :app:classes
> Task :app:jar
> Task :app:startScripts
> Task :app:distTar
> Task :app:distZip
> Task :app:assemble
> Task :app:compileTestJava
> Task :app:processTestResources NO-SOURCE
> Task :app:testClasses
> Task :app:test
> Task :app:check
> Task :app:build
そして、ブランチを切り替えてビルドを実行します。
$ bash gradlew :app:build
> Task :app:clean
> Task :app:compileJava FROM-CACHE
> Task :app:processResources NO-SOURCE
> Task :app:classes UP-TO-DATE
> Task :app:jar
> Task :app:startScripts
> Task :app:distTar
> Task :app:distZip
> Task :app:assemble
> Task :app:compileTestJava FROM-CACHE
> Task :app:processTestResources NO-SOURCE
> Task :app:testClasses UP-TO-DATE
> Task :app:test FROM-CACHE
> Task :app:check UP-TO-DATE
> Task :app:build
FROM-CACHE というラベルを見てください。キャッシュからビルド生成物を取得することに成功しています。
本記事では、gradle を使用したモダンな Java のビルドについてまとめました。私たちは、gradle でビルドした結果を AWS Lambda へアップロードし、サーバーレスな API の構築を日々行っています。
Java × gradle × serverless で圧倒的な開発効率を是非本記事の内容を応用してお試しください!
JavaのAWSサーバーレス開発はお気軽にお問い合わせください。