- はじめに
- スクリプトファイルの命名
- Kotlin と Groovy の言語上の考慮事項
- Gradle init によるプロジェクト生成
- プラグインの適用
- プラグインの設定
- タスクの構成
- タスクの作成
- 依存の指定
- よくある設定
はじめに
Gradle 5.0 よりGradle Kotlin DSL が提供され、groovy によるビルドスクリプトを Kotlin で記載できるようになりました。
Kotlin でビルドスクリプトを書くことで、IDEによるサジェストやコードジャンプなどの恩恵を十分に受けることができますし、タイプセーフでありリファクタリングなども容易となるので、これから Groovy のビルドスクリプトを書くのであれば Gradle Kotlin DSL を使うべきです。
ここでは、Groovy DSL と Kotlin DSL の違いと Kotlin DSL でビルドスクリプトを書くための基礎知識について説明します。
スクリプトファイルの命名
Kotlin DSL を使うには、ビルドスクリプトの拡張子を .gradle
から .gradle.kts
に変更します。
- Groovy DSL スクリプトでは
build.gradle
の拡張子を使用します - Kotlin DSL スクリプトでは
build.gradle.kts
の拡張子を使用します
設定ファイルについても同様で、settings.gradle
は settings.gradle.kts
のような拡張子とします。
initスクリプトなどについても同様に init.gradle
を init.gradle.kts
のように定義します。
Kotlin と Groovy の言語上の考慮事項
Kotlin と Groovy の言語上の違いにより以下を考慮する必要があります。
- Groovy による文字列は
'string'
のように1重引用符または二重引用符で指定できますが、Kotlinでは二重引用符"string"
が必要になります - Groovyでは、関数を呼び出すときに括弧を省略できますが、Kotlin では括弧が必要になります
- Gradle Groovy DSLでは、プロパティの割り当てに
=
を省略できますが、Kotlinでは常に代入演算子が必要になります
build.gradle
の以下の定義は、
// build.gradle group 'com.acme' dependencies { implementation 'com.acme:example:1.0' }
build.gradle.kts
のように記載することになります。
// build.gradle.kts group = "com.acme" dependencies { implementation("com.acme:example:1.0") }
Gradle init によるプロジェクト生成
gradle init
タスクにより Java アプリケーションプロジェクトを Groovy DSL を使う設定とした場合には以下のようなビルドスクリプトが生成されます。
settings.gradle
rootProject.name = 'grs' include('app')
build.gradle
// build.gradle plugins { id 'application' } repositories { jcenter() } dependencies { testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.2' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine' implementation 'com.google.guava:guava:29.0-jre' } application { mainClass = 'grs.App' } tasks.named('test') { useJUnitPlatform() }
一方 Kotlin DSL を使う設定とした場合には以下のようなビルドスクリプトが生成されます。
settings.gradle.kts
rootProject.name = "kts" include("app")
build.gradle.kts
// build.gradle.kts plugins { application } repositories { jcenter() } dependencies { testImplementation("org.junit.jupiter:junit-jupiter-api:5.6.2") testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") implementation("com.google.guava:guava:29.0-jre") } application { mainClass.set("kts.App") } tasks.test { useJUnitPlatform() }
プラグインの指定では id 'application'
が application
のようになっています。
また、mainClass = 'grs.App'
が mainClass.set("kts.App")
となっています。
その他はほとんど同等な形で記載できることがわかります。
プラグインの適用
プラグインの適用は plugins {}
ブロックで宣言的に記載することができます。
Groovy DSL での以下の記載は、
// build.gradle plugins { id 'java' id 'jacoco' id 'maven-publish' id 'org.springframework.boot' version '2.0.2.RELEASE' }
Kotlin DSL では以下のように書きます。
// build.gradle.kts plugins { java jacoco `maven-publish` id("org.springframework.boot") version "2.0.2.RELEASE" }
Kotlin DSL では java
や jacoco
maven-publish
といった Gradle コアプラグインはプロパティ拡張が提供されるため、直接指定できます。
Kotlin ではプロパティ名として -
を使用できないため maven-publish
はバッククオートで囲む必要があります。
サードパーティのプラグインは、Groovy DSL と同じ方法で適用できます(ただし id()
のような形でプラグインIDを指定します)。
プラグインの設定
プラグインの拡張設定は Groovy DSL と同様に設定することができます。
例えば jacoco プラグインの設定は以下のようにすることができます。
// build.gradle.kts plugins { jacoco } jacoco { toolVersion = "0.8.1" }
プラグインを命令的に apply
で適用する場合は以下のように記載します。
// build.gradle.kts apply(plugin = "checkstyle") configure<CheckstyleExtension> { maxErrors = 10 }
ただし、こちらの書き方は推奨されていません。plugins {}
ブロックを使って宣言的にプラグインを適用することでタイプセーフなアクセサーを利用できるようになります。
タスクの構成
build.gradle
によるタスクの構成は以下のようになります。
// build.gradle tasks.jar { archiveFileName = 'foo.jar' }
Kotlin DSL では以下のようになります。
// build.gradle.kts tasks.jar { archiveFileName.set("foo.jar") }
Groovy DSL と Kotlin DSL では記載内容は同様ですが、その動作は異なっており、Kotlin DSL では configuration avoidance API を利用するものになっています。 これは、対象のタスクが実行されるまで その構成を延期することで、タスクの構成のコストを回避します。ビルドの過程で必要の無いコード品質、テスト、公開タスクといった無関係のタスクの構成を実行しません。
Groovy DSL と同様に、eager な構成を行う場合は以下のようにすることができます。
// build.gradle.kts tasks.getByName<Jar>("jar") { archiveFileName.set("foo.jar") }
タスク構成の例として Spring Boot の構成は以下のようになります。
// build.gradle.kts plugins { java id("org.springframework.boot") version "2.3.4.RELEASE" } tasks.bootJar { archiveFileName.set("app.jar") mainClassName = "com.example.demo.Demo" } tasks.bootRun { main = "com.example.demo.Demo" args("--spring.profiles.active=demo") }
タスクの構成は以下のように書くこともできます。
// build.gradle.kts import org.springframework.boot.gradle.tasks.bundling.BootJar import org.springframework.boot.gradle.tasks.run.BootRun plugins { java id("org.springframework.boot") version "2.3.4.RELEASE" } tasks.named<BootJar>("bootJar") { archiveFileName.set("app.jar") mainClassName = "com.example.demo.Demo" } tasks.named<BootRun>("bootRun") { main = "com.example.demo.Demo" args("--spring.profiles.active=demo") }
Kotlin はタイプセーフなので、対象の構成の型を明示する必要があります。
タスクの作成
Groovy DSL によるタスクの作成は以下のようになります。
// build.gradle task greeting { doLast { println 'Hello, World!' } }
Kotlin DSL では以下のように書くことができます。
// build.gradle.kts task("greeting") { doLast { println("Hello, World!") } }
この場合、eager な構成となり、configuration avoidance は適用されません。
以下のように書いても同様となります。
// build.gradle.kts tasks.create("greeting") { doLast { println("Hello, World!") } }
型指定されたタスクは以下のようになります。
// build.gradle.kts tasks.create<Zip>("docZip") { archiveFileName.set("doc.zip") from("doc") }
create()
ではなく register()
とすることで configuration avoidance となり、タスク実行時までその構成が遅延されます。
// build.gradle.kts tasks.register<Zip>("docZip") { archiveFileName.set("doc.zip") from("doc") }
依存の指定
依存関係の宣言は、Groovy DSL と同じように指定できます。
Groovy DSL による以下の宣言は、
// build.gradle plugins { id 'java-library' } dependencies { implementation 'com.example:lib:1.1' runtimeOnly 'com.example:runtime:1.0' testImplementation('com.example:test-support:1.3') { exclude(module: 'junit') } testRuntimeOnly 'com.example:test-junit-jupiter-runtime:1.3' }
Kotlin DSL では以下のようになります。
// build.gradle.kts plugins { `java-library` } dependencies { implementation("com.example:lib:1.1") runtimeOnly("com.example:runtime:1.0") testImplementation("com.example:test-support:1.3") { exclude(module = "junit") } testRuntimeOnly("com.example:test-junit-jupiter-runtime:1.3") }
依存のカスタム構成を使う場合、Groovy DSL の以下の宣言は、
// build.gradle configurations { db integTestImplementation { extendsFrom testImplementation } } dependencies { db 'org.postgresql:postgresql' integTestImplementation 'com.example:integ-test-support:1.3' }
Kotlin DSL では以下のようになります。
// build.gradle.kts val db by configurations.creating val integTestImplementation by configurations.creating { extendsFrom(configurations["testImplementation"]) } dependencies { db("org.postgresql:postgresql") integTestImplementation("com.example:integ-test-support:1.3") }
ただし、上記設定を行った場合、dependencies { }
ブロックでは、db
と integTestImplementation
しか使えなくなります。
他の構成と合わせて利用する場合は、configurations
により委譲プロパティを定義します。
// build.gradle.kts val testRuntimeOnly by configurations val db by configurations.creating val integTestImplementation by configurations.creating { extendsFrom(configurations["testImplementation"]) } dependencies { testRuntimeOnly("com.example:test-junit-jupiter-runtime:1.3") "db"("org.postgresql:postgresql") "integTestImplementation"("com.example:integ-test-support:1.3") }
または文字列リテラルとして指定します。
dependencies { "db"("org.postgresql:postgresql") "integTestImplementation"("com.example:integ-test-support:1.3") }
よくある設定
Java バージョン指定
java { sourceCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11 }
文字エンコーディング指定
tasks {
withType<JavaCompile> {
options.encoding = Charsets.UTF_8.name()
}
// ...
}