// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

:kotlin-reference: https://kotlinlang.org/docs/reference/
:kotlin-tutorials: https://kotlinlang.org/tutorials/
:gradle-issues: https://github.com/gradle/gradle/issues/
:plugin-portal: https://plugins.gradle.org/

[[kotlin_dsl]]
= Gradle Kotlin DSL Primer

Gradle's Kotlin DSL provides an alternative syntax to the traditional Groovy DSL with an enhanced editing experience in supported IDEs, with superior content assist, refactoring, documentation, and more.
This chapter provides details of the main Kotlin DSL constructs and how to use it to interact with the Gradle API.

[TIP]
====
If you are interested in migrating an existing Gradle build to the Kotlin DSL, please also check out the dedicated <<migrating_from_groovy_to_kotlin_dsl.adoc#migrating_groovy_kotlin,migration section>>.
====


[[kotdsl:prerequisites]]
== Prerequisites

* The embedded Kotlin compiler is known to work on Linux, macOS, Windows, Cygwin, FreeBSD and Solaris on x86-64 architectures.
* Knowledge of Kotlin syntax and basic language features is very helpful. The link:{kotlin-reference}[Kotlin reference documentation] and link:https://kotlinlang.org/docs/tutorials/koans.html[Kotlin Koans] will help you to learn the basics.
* Use of the <<plugins#sec:plugins_block,plugins {}>> block to declare Gradle plugins significantly improves the editing experience and is highly recommended.

[[sec:ide_support]]
== IDE support

The Kotlin DSL is fully supported by IntelliJ IDEA and Android Studio. Other IDEs do not yet provide helpful tools for editing Kotlin DSL files, but you can still import Kotlin-DSL-based builds and work with them as usual.

.IDE support matrix
[cols=">.^,^.^,^.^,^.^",frame=none,grid=rows,options="header"]
|===
||Build import|Syntax highlighting ^1^|Semantic editor ^2^

|IntelliJ IDEA
|[.green]#*✓*#
|[.green]#*✓*#
|[.green]#*✓*#

|Android Studio
|[.green]#*✓*#
|[.green]#*✓*#
|[.green]#*✓*#

|Eclipse IDE
|[.green]#*✓*#
|[.green]#*✓*#
|[.red]#✖#

|CLion
|[.green]#*✓*#
|[.green]#*✓*#
|[.red]#✖#

|Apache NetBeans
|[.green]#*✓*#
|[.green]#*✓*#
|[.red]#✖#

|Visual Studio Code ^(LSP)^
|[.green]#*✓*#
|[.green]#*✓*#
|[.red]#✖#

|Visual Studio
|[.green]#*✓*#
|[.red]#✖#
|[.red]#✖#

|===

[%hardbreaks]
^1^ ^Kotlin^ ^syntax^ ^highlighting^ ^in^ ^Gradle^ ^Kotlin^ ^DSL^ ^scripts^
^2^ ^code^ ^completion,^ ^navigation^ ^to^ ^sources,^ ^documentation,^ ^refactorings^ ^etc...^ ^in^ ^Gradle^ ^Kotlin^ ^DSL^ ^scripts^

As mentioned in the limitations, you must link:https://www.jetbrains.com/help/idea/gradle.html#gradle_import[import your project from the Gradle model] to get content-assist and refactoring tools for Kotlin DSL scripts in IntelliJ IDEA.

In addition, IntelliJ IDEA and Android Studio might spawn up to 3 Gradle daemons when editing Gradle scripts — one for each type of script: build scripts, settings files and initialization scripts.
Builds with slow configuration time might affect the IDE responsiveness, so please check out the <<performance.adoc#performance_gradle,performance section>> to help resolve such issues.

=== Automatic build import vs. automatic reloading of script dependencies

Both IntelliJ IDEA and Android Studio — which is derived from IntelliJ IDEA — will detect when you make changes to your build logic and offer two suggestions:

 1. Import the whole build again
+
image::intellij-build-import-popup.png[IntelliJ IDEA, width=300]
+
image::android-studio-build-sync-popup.png[IntelliJ IDEA]
 2. Reload script dependencies when editing a build script
+
image::intellij-script-dependencies-reload.png[Reload script dependencies]

We recommend that you _disable automatic build import_, but _enable automatic reloading of script dependencies_.
That way you get early feedback while editing Gradle scripts and control over when the whole build setup gets synchronized with your IDE.

=== Troubleshooting

The IDE support is provided by two components:

* The Kotlin Plugin used by IntelliJ IDEA/Android Studio
* Gradle

The level of support varies based on the versions of each.

If you run into trouble, the first thing you should try is running `./gradlew tasks` from the command line to see whether your issue is limited to the IDE. If you encounter the same problem from the command line, then the issue is with the build rather than the IDE integration.

If you can run the build successfully from the command line but your script editor is complaining, then you should try restarting your IDE and invalidating its caches.

If the above doesn't work and you suspect an issue with the Kotlin DSL script editor, you can:

* Run `./gradle tasks` to get more details
* Check the logs in one of these locations:
** `$HOME/Library/Logs/gradle-kotlin-dsl` on Mac OS X
** `$HOME/.gradle-kotlin-dsl/log` on Linux
** `$HOME/AppData/Local/gradle-kotlin-dsl/log` on Windows
* Open an issue on the link:{gradle-issues}[Gradle issue tracker], including as much detail as you can.

From version 5.1 onwards, the log directory is cleaned up automatically.
It is checked periodically (at most every 24 hours) and log files are deleted if they haven’t been used for 7 days.

If the above isn't enough to pinpoint the problem, you can enable the `org.gradle.kotlin.dsl.logging.tapi` system property in your IDE. This will cause the Gradle Daemon to log extra information in its log file located in `$HOME/.gradle/daemon`. In IntelliJ IDEA this can be done by opening `Help > Edit Custom VM Options...` and adding `-Dorg.gradle.kotlin.dsl.logging.tapi=true`.

For IDE problems outside of the Kotlin DSL script editor, please open issues in the corresponding IDE's issue tracker:

* link:[JetBrains's IDEA issue tracker],
* link:[Google's Android Studio issue tracker].

Lastly, if you face problems with Gradle itself or with the Kotlin DSL, please open issues on the link:{gradle-issues}[Gradle issue tracker].


[[sec:scripts]]
== Kotlin DSL scripts

Just like the Groovy-based equivalent, the Kotlin DSL is implemented on top of Gradle's Java API.
Everything you can read in a Kotlin DSL script is Kotlin code compiled and executed by Gradle.
Many of the objects, functions and properties you use in your build scripts come from the Gradle API and the APIs of the applied plugins.

=== Script file names

[NOTE]
====
Groovy DSL script files use the `.gradle` file name extension.

Kotlin DSL script files use the `.gradle.kts` file name extension.
====

To activate the Kotlin DSL, simply use the `.gradle.kts` extension for your build scripts in place of `.gradle`. That also applies to the <<build_lifecycle#sec:settings_file,settings file>> — for example `settings.gradle.kts` — and <<init_scripts#init_scripts,initialization scripts>>.

Note that you can mix Groovy DSL build scripts with Kotlin DSL ones, i.e. a Kotlin DSL build script can apply a Groovy DSL one and each project in a multi-project build can use either one.

We recommend that you apply the following conventions to get better IDE support:

* Name settings scripts (or any script that is backed by a Gradle `Settings` object) according to the pattern `*.settings.gradle.kts` — this includes script plugins that are applied from settings scripts
* Name <<init_scripts#init_scripts,initialization scripts>> according to the pattern `*.init.gradle.kts` or simply `init.gradle.kts`.

This is so that the IDE knows what type of object "backs" the script, be it link:{groovyDslPath}/org.gradle.api.Project.html[Project], link:{groovyDslPath}/org.gradle.api.initialization.Settings.html[Settings] or link:{groovyDslPath}/org.gradle.api.invocation.Gradle.html[Gradle].

[[sec:implicit_imports]]
=== Implicit imports

All Kotlin DSL build scripts have implicit imports consisting of:

* The <<writing_build_scripts#script-default-imports,default Gradle API imports>>
* The Kotlin DSL API, which is all types within the `org.gradle.kotlin.dsl` and `org.gradle.kotlin.dsl.plugins.dsl` packages currently

[CAUTION]
.Avoid using internal Kotlin DSL APIs
====
Use of internal Kotlin DSL APIs in plugins and build scripts has the potential to break builds when either Gradle or plugins change.
The link:{kotlinDslPath}/[Kotlin DSL API] extends the <<authoring_maintainable_build_scripts#sec:avoiding_gradle_internal_apis,Gradle public API>> with the types listed in the https://gradle.github.io/kotlin-dsl-docs/api/[corresponding API docs] that are in the `org.gradle.kotlin.dsl` or `org.gradle.kotlin.dsl.plugins.dsl` packages (but not subpackages of those).
====


[[sec:configuring_plugins]]
[[type-safe-accessors]]
== Type-safe model accessors

The Groovy DSL allows you to reference many elements of the build model by name, even when they are defined at runtime. Think named configurations, named source sets, and so on. For example, you can get hold of the `implementation` configuration via `configurations.implementation`.

The Kotlin DSL replaces such dynamic resolution with type-safe model accessors that work with model elements contributed by plugins.

[[kotdsl:accessor_applicability]]
=== Understanding when type-safe model accessors are available

The Kotlin DSL currently supports type-safe model accessors for any of the following that are contributed by plugins:

* Dependency and artifact configurations (such as `implementation` and `runtimeOnly` contributed by the Java Plugin)
* Project extensions and conventions (such as `sourceSets`)
* Elements in the `tasks` and `configurations` containers
* Elements in <<kotdsl:containers,project-extension containers>> (for example the source sets contributed by the Java Plugin that are added to the `sourceSets` container)
* Extensions on each of the above

[IMPORTANT]
====
Only the main project build scripts and precompiled project script plugins have type-safe model accessors.
Initialization scripts, settings scripts, script plugins do not.
These limitations will be removed in a future Gradle release.
====

The set of type-safe model accessors available is calculated right before evaluating the script body, immediately after the `plugins {}` block.
Any model elements contributed after that point do not work with type-safe model accessors.
For example, this includes any configurations you might define in your own build script.
However, this approach does mean that you can use type-safe accessors for any model elements that are contributed by plugins that are _applied by parent projects_.

The following project build script demonstrates how you can access various configurations, extensions and other elements using type-safe accessors:

.Using type-safe model accessors
====
include::sample[dir="snippets/kotlinDsl/accessors/kotlin",files="build.gradle.kts[tags=accessors]"]
====
<1> Uses type-safe accessors for the `api`, `implementation` and `testImplementation` dependency configurations contributed by the <<java_library_plugin#java_library_plugin,Java Library Plugin>>
<2> Uses an accessor to configure the `sourceSets` project extension
<3> Uses an accessor to configure the `main` source set
<4> Uses an accessor to configure the `java` source for the `main` source set
<5> Uses an accessor to configure the `test` task

[TIP]
====
Your IDE knows about the type-safe accessors, so it will include them in its suggestions.
This will happen both at the top level of your build scripts — most plugin extensions are added to the `Project` object — and within the blocks that configure an extension.
====

Note that accessors for elements of containers such as `configurations`, `tasks` and `sourceSets` leverage Gradle's <<lazy_configuration#lazy_configuration,configuration avoidance APIs>>.
For example, on `tasks` they are of type `TaskProvider<T>` and provide a lazy reference and lazy configuration of the underlying task.
Here are some examples that illustrate the situations in which configuration avoidance applies:

[source,kotlin]
----
tasks.test {
    // lazy configuration
}

// Lazy reference
val testProvider: TaskProvider<Test> = tasks.test

testProvider {
    // lazy configuration
}

// Eagerly realized Test task, defeat configuration avoidance if done out of a lazy context
val test: Test = tasks.test.get()
----

For all other containers than `tasks`, accessors for elements are of type `NamedDomainObjectProvider<T>` and provide the same behavior.

[[sec:kotlin_using_standard_api]]
=== Understanding what to do when type-safe model accessors are not available

Consider the sample build script shown above that demonstrates the use of type-safe accessors.
The following sample is exactly the same except that is uses the `apply()` method to apply the plugin.
The build script can not use type-safe accessors in this case because the `apply()` call happens in the body of the build script.
You have to use other techniques instead, as demonstrated here:

.Configuring plugins without type-safe accessors
====
include::sample[dir="snippets/kotlinDsl/noAccessors/kotlin",files="build.gradle.kts[tags=no-accessors]"]
====

Type-safe accessors are unavailable for model elements contributed by the following:

 * Plugins applied via the `apply(plugin = "id")` method
 * The project build script
 * Script plugins, via `apply(from = "script-plugin.gradle.kts")`
 * Plugins applied via <<sec:kotlin_cross_project_configuration,cross-project configuration>>

You also can not use type-safe accessors in Binary Gradle plugins implemented in Kotlin.

If you can't find a type-safe accessor, _fall back to using the normal API_ for the corresponding types.
To do that, you need to know the names and/or types of the configured model elements.
We'll now show you how those can be discovered by looking at the above script in detail.

==== Artifact configurations

The following sample demonstrates how to reference and configure artifact configurations without type accessors:

.Artifact configurations
====
include::sample[dir="snippets/kotlinDsl/noAccessors/kotlin",files="build.gradle.kts[tags=dependencies]"]
====

The code looks similar to that for the type-safe accessors, except that the configuration names are string literals in this case.
You can use string literals for configuration names in dependency declarations and within the `configurations {}` block.

The IDE won't be able to help you discover the available configurations in this situation, but you can look them up either in the corresponding plugin's documentation or by running `gradle dependencies`.

==== Project extensions and conventions

Project extensions and <<#sec:kotlin_dsl_about_conventions,conventions>> have both a name and a unique type, but the Kotlin DSL only needs to know the type in order to configure them.
As the following sample shows for the `sourceSets {}` and `java {}` blocks from the original example build script, you can use the link:{kotlinDslPath}/org.gradle.kotlin.dsl/org.gradle.api.-project/configure.html[`configure<T>()`] function with the corresponding type to do that:

.Project extensions and conventions
====
include::sample[dir="snippets/kotlinDsl/noAccessors/kotlin",files="build.gradle.kts[tags=project-extension]"]
====

Note that `sourceSets` is a Gradle extension on `Project` of type `SourceSetContainer` and `java` is an extension on `Project` of type `JavaPluginExtension`.

You can discover what extensions and conventions are available either by looking at the documentation for the applied plugins or by running `gradle kotlinDslAccessorsReport`, which prints the Kotlin code necessary to access the model elements contributed by all the applied plugins.
The report provides both names and types.
As a last resort, you can also check a plugin's source code, but that shouldn't be necessary in the majority of cases.

Note that you can also use the link:{kotlinDslPath}/org.gradle.kotlin.dsl/org.gradle.api.-project/the.html[`the<T>()`] function if you only need a reference to the extension or convention without configuring it, or if you want to perform a one-line configuration, like so:

[source,kotlin]
----
the<SourceSetContainer>()["main"].srcDir("src/core/java")
----

The snippet above also demonstrates one way of configuring the elements of a project extension that is a container.

==== Elements in project-extension containers

Container-based project extensions, such as `SourceSetContainer`, also allow you to configure the elements held by them.
In our sample build script, we want to configure a source set named `main` within the source set container, which we can do by using the link:{javadocPath}/org/gradle/api/NamedDomainObjectCollection.html#named-java.lang.String-[named()] method in place of an accessor, like so:

.Elements of project extensions that are containers
====
include::sample[dir="snippets/kotlinDsl/noAccessors/kotlin",files="build.gradle.kts[tags=project-container-extension]"]
====

All elements within a container-based project extension have a name, so you can use this technique in all such cases.

As for project extensions and conventions themselves, you can discover what elements are present in any container by either looking at the documentation of the applied plugins or by running `gradle kotlinDslAccessorsReport`.
And as a last resort, you may be able to view the plugin's source code to find out what it does, but that shouldn't be necessary in the majority of cases.

==== Tasks

Tasks are not managed through a container-based project extension, but they are part of a container that behaves in a similar way.
This means that you can configure tasks in the same way as you do for source sets, as you can see in this example:

.Tasks
====
include::sample[dir="snippets/kotlinDsl/noAccessors/kotlin",files="build.gradle.kts[tags=tasks]"]
====

We are using the Gradle API to refer to the tasks by name and type, rather than using accessors.
Note that it's necessary to specify the type of the task explicitly, otherwise the script won't compile because the inferred type will be `Task`, not `Test`, and the `testLogging` property is specific to the `Test` task type.
You can, however, omit the type if you only need to configure properties or to call methods that are common to all tasks, i.e. they are declared on the `Task` interface.

One can discover what tasks are available by running `gradle tasks`. You can then find out the type of a given task by running `gradle help --task <taskName>`, as demonstrated here:

[source]
----
❯ ./gradlew help --task test
...
Type
     Test (org.gradle.api.tasks.testing.Test)
----

Note that the IDE can assist you with the required imports, so you only need the simple names of the types, i.e. without the package name part.
In this case, there's no need to import the `Test` task type as it is part of the Gradle API and is therefore <<kotlin_dsl#sec:implicit_imports,imported implicitly>>.

[[sec:kotlin_dsl_about_conventions]]
=== About conventions

Some of the Gradle core plugins expose configurability with the help of a so-called _convention_ object.
These serve a similar purpose to — and have now been superseded by — _extensions_.
Please avoid using convention objects when writing new plugins.
The long term plan is to migrate all Gradle core plugins to use extensions and remove the convention objects altogether.

As seen above, the Kotlin DSL provides accessors only for convention objects on `Project`.
There are situations that require you to interact with a Gradle plugin that uses convention objects on other types.
The Kotlin DSL provides the `withConvention(T::class) {}` extension function to do this:

.Configuring source set conventions
====
include::sample[dir="snippets/kotlinDsl/sourceSetConvention/kotlin",files="build.gradle.kts[tags=source-set-convention]"]
====

This technique is most commonly required for source sets that are added by language plugins other than the Java Plugin, e.g. the Groovy Plugin and the Scala Plugin. You can see which plugins add which properties to source sets in the link:{groovyDslPath}/org.gradle.api.tasks.SourceSet.html[SourceSet] reference documentation.

[[kotdsl:multi_project_builds]]
[[sec:multi_project_builds]]
== Multi-project builds

As with single-project builds, you should try to use the `plugins {}` block in your multi-project builds so that you can use the type-safe accessors. Another consideration with multi-project builds is that you won't be able to use type-safe accessors when configuring subprojects within the root build script or with other forms of cross configuration between projects. We discuss both topics in more detail in the following sections.

[[sec:multi_project_builds_applying_plugins]]
=== Applying plugins

You can declare your plugins within the subprojects to which they apply, but we recommend that you also declare them within the root project build script. This makes it easier to keep plugin versions consistent across projects within a build. The approach also improves the performance of the build.

The <<plugins#sec:subprojects_plugins_dsl,Using Gradle plugins>> chapter explains how you can declare plugins in the root project build script with a version and then apply them to the appropriate subprojects' build scripts. What follows is an example of this approach using three subprojects and three plugins. Note how the root build script only declares the community plugins as the Java Library Plugin is tied to the version of Gradle you are using:

[[ex:multi_project_ratpack]]
.Declare plugin dependencies in the root build script using the `plugins {}` block
====
include::sample[dir="snippets/kotlinDsl/multiProjectBuild/kotlin",files="settings.gradle.kts[tags=base];build.gradle.kts[tags=root];domain/build.gradle.kts[];infra/build.gradle.kts[];http/build.gradle.kts[]"]
====

If your build requires additional plugin repositories on top of the Gradle Plugin Portal, you should declare them in the `pluginManagement {}` block in your `settings.gradle.kts` file, like so:

.Declare additional plugin repositories
====
include::sample[dir="snippets/kotlinDsl/multiProjectBuild/kotlin",files="settings.gradle.kts[tags=repositories]"]
====

Plugins fetched from a source other than the link:https://plugins.gradle.org/[Gradle Plugin Portal] can only be declared via the `plugins {}` block if they are published with their <<plugins#sec:plugin_markers,plugin marker artifacts>>.

NOTE: At the time of writing, all versions of the Android Plugin for Gradle up to 3.2.0 present in the `google()` repository lack plugin marker artifacts.

If those artifacts are missing, then you can't use the `plugins {}` block. You must instead fall back to declaring your plugin dependencies using the `buildscript {}` block in the root project build script. Here's an example of doing that for the Android Plugin:

.Declare plugin dependencies in the root build script using the `buildscript {}` block
====
include::sample[dir="snippets/kotlinDsl/androidBuild/kotlin",files="settings.gradle.kts[tags=android];build.gradle.kts[tags=android-buildscript];lib/build.gradle.kts[tags=android];app/build.gradle.kts[tags=android]"]
====

This technique is not that different from what Android Studio produces when creating a new build.
The main difference is that the subprojects' build scripts in the above sample declare their plugins using the `plugins {}` block. This means that you can use type-safe accessors for the model elements that they contribute.

Note that you can't use this technique if you want to apply such a plugin either to the root project build script of a multi-project build (rather than solely to its subprojects) or to a single-project build. You'll need to use a different approach in those cases that we detail in <<kotlin_dsl#sec:plugins_resolution_strategy,another section>>.

[[sec:kotlin_cross_project_configuration]]
=== Cross-configuring projects

<<sharing_build_logic_between_subprojects#sec:convention_plugins_vs_cross_configuration,Cross project configuration>> is a mechanism by which you can configure a project from another project's build script. A common example is when you configure subprojects in the root project build script.

Taking this approach means that you won't be able to use type-safe accessors for model elements contributed by the plugins. You will instead have to rely on string literals and the standard Gradle APIs.

As an example, let's modify the <<ex:multi_project_ratpack,Java/Ratpack sample build>> to fully configure its subprojects from the root project build script:

.Cross-configuring projects
====
include::sample[dir="snippets/kotlinDsl/multiProjectBuild/kotlin",files="settings.gradle.kts[tags=base];build.gradle.kts[tags=cross]"]
====

Note how we're using the `apply()` method to apply the plugins since the `plugins {}` block doesn't work in this context.
We are also using standard APIs instead of type-safe accessors to configure tasks, extensions and conventions — an approach that we discussed in <<kotlin_dsl#sec:kotlin_using_standard_api,more detail elsewhere>>.

[[sec:plugins_resolution_strategy]]
== When you can't use the `plugins {}` block

Plugins fetched from a source other than the link:https://plugins.gradle.org/[Gradle Plugin Portal] may or may not be usable with the `plugins {}` block.
It depends on how they have been published and, specifically, whether they have been published with the necessary <<plugins#sec:plugin_markers,plugin marker artifacts>>.

For example, the Android Plugin for Gradle is not published to the Gradle Plugin Portal and — at least up to version 3.2.0 of the plugin — the metadata required to resolve the artifacts for a given plugin identifier is not published to the Google repository.

If your build is a multi-project build and you don't need to apply such a plugin to your _root_ project, then you can get round this issue using the technique <<kotlin_dsl#sec:multi_project_builds_applying_plugins,described above>>.
For any other situation, keep reading.

[TIP]
====
When publishing plugins, please use Gradle's built-in <<java_gradle_plugin#java_gradle_plugin,Gradle Plugin Development Plugin>>.
It automates the publication of the metadata necessary to make your plugins usable with the `plugins {}` block.
====

We will show you in this section how to apply the Android Plugin to a single-project build or the root project of a multi-project build.
The goal is to instruct your build on how to map the `com.android.application` plugin identifier to a resolvable artifact.
This is done in two steps:

* Add a plugin repository to the build's settings script
* Map the plugin ID to the corresponding artifact coordinates

You accomplish both steps by configuring a `pluginManagement {}` block in the build's settings script.
To demonstrate, the following sample adds the `google()` repository — where the Android plugin is published — to the repository search list, and uses a `resolutionStrategy {}` block to map the `com.android.application` plugin ID to the `com.android.tools.build:gradle:<version>` artifact available in the `google()` repository:

.Mapping plugin IDs to dependency coordinates
====
include::sample[dir="snippets/kotlinDsl/androidSingleBuild/kotlin",files="settings.gradle.kts[tags=android];build.gradle.kts[tags=android]"]
====

In fact, the above sample will work for all `com.android.*` plugins that are provided by the specified module. That's because the packaged module contains the details of which plugin ID maps to which plugin implementation class, using the properties-file mechanism described in the <<custom_plugins#sec:custom_plugins_standalone_project,Writing Custom Plugins>> chapter.

See the <<plugins#sec:plugin_management,Plugin Management>> section of the Gradle user manual for more information on the `pluginManagement {}` block and what it can be used for.

// [PL] It seems to me that this block of content should really be in a more generic part
//      of the user manual as it discusses techniques that apply outside of the Kotlin DSL.
//      In fact, it indicates missing content that this chapter should be able to link to.
//
// In the case of multi-project builds, this approach is similar to using a `buildscript {}` block in the root project build script to depend on third party plugins and then using `plugins {}` in your sub project build scripts to apply them.
// The main difference is that this approach means that the root project can also benefit from the `plugins {}` block and it is more aligned with Gradle best practices.
//
// [PL] We should also aim to avoid temporary information in the user manual that could
//      be out of date at any time.
// The same approach can be used to resolve plugins from composite builds, which link:https://github.com/gradle/gradle/issues/2528[do not expose plugin markers] yet.
// Simply map the plugin ID to the corresponding artifact coordinates as shown in the Android samples above.


// TODO ?
// [[sec:buildSrc]]
// == Using `buildSrc`
//
// 1. what is buildSrc -> link
// 2. apply the `kotlin-dsl` plugin, see below for the details
// 3. all dependencies added to `buildSrc/build.gradle.kts` will be available to all build scripts
// 3. all members from `buildSrc/src/main/kotlin` will be available to all build scripts
// 4. handy for constants, objects, functions, extension functions
// 5. perfect for Gradle Tasks, Gradle Plugins and DSL Extensions


[[kotdsl:containers]]
== Working with container objects

The Gradle build model makes heavy use of container objects (or just "containers").
For example, both `configurations` and `tasks` are container objects that contain `Configuration` and `Task` objects respectively.
Community plugins also contribute containers, like the `android.buildTypes` container contributed by the Android Plugin.

The Kotlin DSL provides several ways for build authors to interact with containers.
We look at each of those ways next, using the `tasks` container as an example.

[TIP]
====
Note that you can leverage the type-safe accessors described in <<kotdsl:accessor_applicability,another section>> if you are configuring existing elements on supported containers. That section also describes which containers support type-safe accessors.
====


=== Using the container API

All containers in Gradle implement link:{groovyDslPath}/org.gradle.api.NamedDomainObjectContainer.html#org.gradle.api.NamedDomainObjectContainer[NamedDomainObjectContainer<DomainObjectType>].
Some of them can contain objects of different types and implement link:{groovyDslPath}/org.gradle.api.PolymorphicDomainObjectContainer.html#org.gradle.api.PolymorphicDomainObjectContainer[PolymorphicDomainObjectContainer<BaseType>].
The simplest way to interact with containers is through these interfaces.

The following sample demonstrates how you can use the link:{groovyDslPath}/org.gradle.api.NamedDomainObjectContainer.html#org.gradle.api.NamedDomainObjectContainer:named(java.lang.String)[named()] method to configure existing tasks and the link:{groovyDslPath}/org.gradle.api.NamedDomainObjectContainer.html#org.gradle.api.NamedDomainObjectContainer:register(java.lang.String)[register()] method to create new ones.

.Using the container API
====
include::sample[dir="snippets/kotlinDsl/containers-api/kotlin",files="build.gradle.kts[tags=api]"]
====
<1> Gets a reference of type `Task` to the existing task named `check`
<2> Registers a new untyped task named `myTask1`
<3> Gets a reference to the existing task named `compileJava` of type `JavaCompile`
<4> Registers a new task named `myCopy1` of type `Copy`
<5> Gets a reference to the existing (untyped) task named `assemble` and configures it — you can only configure properties and methods that are available on `Task` with this syntax
<6> Registers a new untyped task named `myTask2` and configures it — you can only configure properties and methods that are available on `Task` in this case
<7> Gets a reference to the existing task named `test` of type `Test` and configures it — in this case you have access to the properties and methods of the specified type
<8> Registers a new task named `myCopy2` of type `Copy` and configures it

[NOTE]
====
The above sample relies on the configuration avoidance APIs. If you need or want to eagerly configure or register container elements, simply replace `named()` with `getByName()` and `register()` with `create()`.
====

=== Using Kotlin delegated properties

Another way to interact with containers is via Kotlin delegated properties.
These are particularly useful if you need a reference to a container element that you can use elsewhere in the build.
In addition, Kotlin delegated properties can easily be renamed via IDE refactoring.

The following sample does the exact same things as the one in the previous section, but it uses delegated properties and reuses those references in place of string-literal task paths:

.Using Kotlin delegated properties
====
include::sample[dir="snippets/kotlinDsl/containers-delegated-properties/kotlin",files="build.gradle.kts[tags=delegated-properties]"]
====
<1> Uses the reference to the `myTask1` task rather than a task path


[NOTE]
====
The above rely on configuration avoidance APIs. If you need to eagerly configure or register container elements simply replace link:{kotlinDslPath}/org.gradle.kotlin.dsl/org.gradle.api.-named-domain-object-container/existing.html[`existing()`] with link:{kotlinDslPath}/org.gradle.kotlin.dsl/org.gradle.api.-named-domain-object-container/getting.html[`getting()`] and link:{kotlinDslPath}/org.gradle.kotlin.dsl/org.gradle.api.-named-domain-object-container/registering.html[`registering()`] with link:{kotlinDslPath}/org.gradle.kotlin.dsl/org.gradle.api.-named-domain-object-container/creating.html[`creating()`].
====

=== Configuring multiple container elements together

When configuring several elements of a container one can group interactions in a block in order to avoid repeating the container's name on each interaction.
The following example uses a combination of type-safe accessors, the container API and Kotlin delegated properties:

.Container scope
====
include::sample[dir="snippets/kotlinDsl/containers-scope/kotlin",files="build.gradle.kts[tags=scope]"]
====

// TODO decide if we should document this given the current limitation
// === The container scope string invoke extension
//
// .The container scope string invoke extension
// ====
// include::sample[dir="snippets/kotlinDsl/containers-string-invoke/kotlin",files="build.gradle.kts[tags=string-invoke]"]
// ====


[[kotdsl:properties]]
== Working with runtime properties

Gradle has two main sources of properties that are defined at runtime: <<build_environment#sec:project_properties,_project properties_>> and <<writing_build_scripts#sec:extra_properties,_extra properties_>>.
The Kotlin DSL provides specific syntax for working with these types of properties, which we look at in the following sections.

=== Project properties

The Kotlin DSL allows you to access project properties by binding them via Kotlin delegated properties.
Here's a sample snippet that demonstrates the technique for a couple of project properties, one of which _must_ be defined:

.build.gradle.kts
[source,kotlin]
----
val myProperty: String by project  // <1>
val myNullableProperty: String? by project // <2>
----
<1> Makes the `myProperty` project property available via a `myProperty` delegated property — the project property must exist in this case, otherwise the build will fail when the build script attempts to use the `myProperty` value
<2> Does the same for the `myNullableProperty` project property, but the build won't fail on using the `myNullableProperty` value as long as you check for null (standard https://kotlinlang.org/docs/reference/null-safety.html[Kotlin rules for null safety] apply)

The same approach works in both settings and initialization scripts, except you use `by settings` and `by gradle` respectively in place of `by project`.

=== Extra properties

Extra properties are available on any object that implements the link:{groovyDslPath}/org.gradle.api.plugins.ExtensionAware.html#org.gradle.api.plugins.ExtensionAware[ExtensionAware] interface.
Kotlin DSL allows you to access extra properties and create new ones via delegated properties, using any of the `by extra` forms demonstrated in the following sample:

.build.gradle.kts
[source,kotlin]
----
val myNewProperty by extra("initial value")  // <1>
val myOtherNewProperty by extra { "calculated initial value" }  // <2>

val myProperty: String by extra  // <3>
val myNullableProperty: String? by extra  // <4>
----
<1> Creates a new extra property called `myNewProperty` in the current context (the project in this case) and initializes it with the value `"initial value"`, which also determines the property's _type_
<2> Create a new extra property whose initial value is calculated by the provided lambda
<3> Binds an existing extra property from the current context (the project in this case) to a `myProperty` reference
<4> Does the same as the previous line but allows the property to have a null value

This approach works for all Gradle scripts: project build scripts, script plugins, settings scripts and initialization scripts.

You can also access extra properties on a root project from a subproject using the following syntax:

.my-sub-project/build.gradle.kts
[source,kotlin]
----
val myNewProperty: String by rootProject.extra  // <1>
----
<1> Binds the root project's `myNewProperty` extra property to a reference of the same name

Extra properties aren't just limited to projects.
For example, `Task` extends `ExtensionAware`, so you can attach extra properties to tasks as well.
Here's an example that defines a new `myNewTaskProperty` on the `test` task and then uses that property to initialize another task:

.build.gradle.kts
[source,kotlin]
----
tasks {
    test {
        val reportType by extra("dev")  // <1>
        doLast {
            // Use 'suffix' for post processing of reports
        }
    }

    register<Zip>("archiveTestReports") {
        val reportType: String by test.get().extra  // <2>
        archiveAppendix.set(reportType)
        from(test.get().reports.html.destination)
    }
}
----
<1> Creates a new `reportType` extra property on the `test` task
<2> Makes the `test` task's `reportType` extra property available to configure the `archiveTestReports` task

If you're happy to use eager configuration rather than the configuration avoidance APIs, you could use a single, "global" property for the report type, like this:

.build.gradle.kts
[source,kotlin]
----
tasks.test.doLast { ... }

val testReportType by tasks.test.get().extra("dev")  // <1>

tasks.create<Zip>("archiveTestReports") {
    archiveAppendix.set(testReportType)  // <2>
    from(test.get().reports.html.destination)
}
----
<1> Creates and initializes an extra property on the `test` task, binding it to a "global" property
<2> Uses the "global" property to initialize the `archiveTestReports` task

There is one last syntax for extra properties that we should cover, one that treats `extra` as a map.
We recommend against using this in general as you lose the benefits of Kotlin's type checking and it prevents IDEs from providing as much support as they could.
However, it is more succinct than the delegated properties syntax and can reasonably be used if you only need to set the value of an extra property without referencing it later.

Here's a simple example demonstrating how to set and read extra properties using the map syntax:

.build.gradle.kts
[source,kotlin]
----
extra["myNewProperty"] = "initial value"  // <1>

tasks.create("myTask") {
    doLast {
        println("Property: ${project.extra["myNewProperty"]}")  // <2>
    }
}
----
<1> Creates a new project extra property called `myNewProperty` and sets its value
<2> Reads the value from the project extra property we created — note the `project.` qualifier on `extra[...]`, otherwise Gradle will assume we want to read an extra property from the _task_

// === `Property`, `Provider` and `NamedDomainObjectProvider`


[[sec:kotlin-dsl_plugin]]
== The Kotlin DSL Plugin

The Kotlin DSL Plugin provides a convenient way to develop Kotlin-based projects that contribute build logic.
That includes <<organizing_gradle_projects#sec:build_sources,buildSrc projects>>, <<composite_builds#composite_builds,included builds>> and <<custom_plugins#custom_plugins,Gradle plugins>>.

The plugin achieves this by doing the following:

 * Applies the link:https://kotlinlang.org/docs/reference/using-gradle.html#targeting-the-jvm[Kotlin Plugin], which adds support for compiling Kotlin source files.
 * Adds the `kotlin-stdlib-jdk8`, `kotlin-reflect` and `gradleKotlinDsl()` dependencies to the `compileOnly` and `testImplementation` configurations, which allows you to make use of those Kotlin libraries and the Gradle API in your Kotlin code.
 * Configures the Kotlin compiler with the same settings that are used for Kotlin DSL scripts, ensuring consistency between your build logic and those scripts.
 * Enables support for <<custom_plugins#sec:precompiled_plugins,precompiled script plugins>>.

[CAUTION]
.Avoid specifying a version for the `kotlin-dsl` plugin
====
Each Gradle release is meant to be used with a specific version of the `kotlin-dsl` plugin and compatibility between arbitrary Gradle releases and `kotlin-dsl` plugin versions is not guaranteed. Using an unexpected version of the `kotlin-dsl` plugin in a build will emit a warning and can cause hard to diagnose problems.
====

This is the basic configuration you need to use the plugin:

.Applying the Kotlin DSL Plugin to a `buildSrc` project
====
include::sample[dir="snippets/kotlinDsl/kotlinDslPlugin/kotlin",files="buildSrc/build.gradle.kts[tags=apply]"]
====

[[sec:kotlin]]
== The embedded Kotlin

Gradle embeds Kotlin in order to provide support for Kotlin-based scripts.

=== Kotlin versions

Gradle ships with `kotlin-compiler-embeddable` plus matching versions of `kotlin-stdlib` and `kotlin-reflect` libraries. For example, Gradle 4.3 ships with the Kotlin DSL v0.12.1 that includes Kotlin 1.1.51 versions of these modules. The `kotlin` package from those modules is visible through the Gradle classpath.

The link:https://kotlinlang.org/docs/reference/compatibility.html[compatibility guarantees] provided by Kotlin apply for both backward and forward compatibility.

==== Backward compatibility

Our approach is to only do backwards-breaking Kotlin upgrades on a major Gradle release. We will always clearly document which Kotlin version we ship and announce upgrade plans before a major release.

Plugin authors who want to stay compatible with older Gradle versions need to limit their API usage to a subset that is compatible with these old versions. It’s not really different from any other new API in Gradle. E.g. if we introduce a new API for dependency resolution and a plugin wants to use that API, then they either need to drop support for older Gradle versions or they need to do some clever organization of their code to only execute the new code path on newer versions.

==== Forward compatibility

The biggest issue is the compatibility between the external `kotlin-gradle-plugin` version and the `kotlin-stdlib` version shipped with Gradle. More generally, between any plugin that transitively depends on `kotlin-stdlib` and its version shipped with Gradle. As long as the combination is compatible everything should work. This will become less of an issue as the language matures.

[[sec:kotlin_compiler_arguments]]
=== Kotlin compiler arguments

These are the Kotlin compiler arguments used for compiling Kotlin DSL scripts and Kotlin sources and scripts in a project that has the `kotlin-dsl` plugin applied:

`-jvm-target=1.8`::
Sets the target version of the generated JVM bytecode to `1.8`.

`-Xjsr305=strict`::
Sets up Kotlin's Java interoperability to strictly follow JSR-305 annotations for increased null safety.
See link:https://kotlinlang.org/docs/reference/java-interop.html#compiler-configuration[Calling Java code from Kotlin] in the Kotlin documentation for more information.

[[sec:interoperability]]
== Interoperability

When mixing languages in your build logic, you may have to cross language boundaries.
An extreme example would be a build that uses tasks and plugins that are implemented in Java, Groovy and Kotlin, while also using both Kotlin DSL and Groovy DSL build scripts.

Quoting the Kotlin reference documentation:

> Kotlin is designed with Java Interoperability in mind. Existing Java code can be called from Kotlin in a natural way, and Kotlin code can be used from Java rather smoothly as well.

Both link:{kotlin-reference}java-interop.html[calling Java from Kotlin] and link:{kotlin-reference}java-to-kotlin-interop.html[calling Kotlin from Java] are very well covered in the Kotlin reference documentation.

The same mostly applies to interoperability with Groovy code.
In addition, the Kotlin DSL provides several ways to opt into Groovy semantics, which we look at next.

=== Static extensions

Both the Groovy and Kotlin languages support extending existing classes via link:https://groovy-lang.org/metaprogramming.html#_extension_modules[Groovy Extension modules] and link:{kotlin-reference}extensions.html[Kotlin extensions].

To call a Kotlin extension function from Groovy, call it as a static function, passing the receiver as the first parameter:

.Calling a Kotlin extension from Groovy
====
include::sample[dir="snippets/kotlinDsl/interoperability-static-extensions/kotlin",files="build.gradle[tags=kotlin-from-groovy]"]
====

Kotlin extension functions are package-level functions and you can learn how to locate the name of the type declaring a given Kotlin extension in the link:{kotlin-reference}java-to-kotlin-interop.html#package-level-functions[Package-Level Functions] section of the Kotlin reference documentation.

To call a Groovy extension method from Kotlin, the same approach applies: call it as a static function passing the receiver as the first parameter.
Here's an example:

.Calling a Groovy extension from Kotlin
====
include::sample[dir="snippets/kotlinDsl/interoperability-static-extensions/kotlin",files="build.gradle.kts[tags=groovy-from-kotlin]"]
====

=== Named parameters and default arguments

Both the Groovy and Kotlin languages support named function parameters and default arguments, although they are implemented very differently.
Kotlin has fully-fledged support for both, as described in the Kotlin language reference under link:{kotlin-reference}functions.html#named-arguments[named arguments] and link:{kotlin-reference}functions.html#default-arguments[default arguments].
Groovy implements link:https://groovy-lang.org/objectorientation.html#_named_arguments[named arguments] in a non-type-safe way based on a `Map<String, ?>` parameter, which means they cannot be combined with link:https://groovy-lang.org/objectorientation.html#_default_arguments[default arguments].
In other words, you can only use one or the other in Groovy for any given method.

==== Calling Kotlin from Groovy

To call a Kotlin function that has named arguments from Groovy, just use a normal method call with positional parameters.
There is no way to provide values by argument name.

To call a Kotlin function that has default arguments from Groovy, always pass values for all the function parameters.

==== Calling Groovy from Kotlin

To call a Groovy function with named arguments from Kotlin, you need to pass a `Map<String, ?>`, as shown in this example:

.Call Groovy function with named arguments from Kotlin
[.multi-language-sample]
====
.build.gradle.kts
[source, kotlin]
----
groovyNamedArgumentTakingMethod(mapOf(
    "parameterName" to "value",
    "other" to 42,
    "and" to aReference))
----
====

To call a Groovy function with default arguments from Kotlin, always pass values for all the parameters.

=== Groovy closures from Kotlin

You may sometimes have to call Groovy methods that take link:https://groovy-lang.org/closures.html[Closure] arguments from Kotlin code.
For example, some third-party plugins written in Groovy expect closure arguments.

[NOTE]
====
Gradle plugins written in any language should prefer the type `Action<T>` type in place of closures. Groovy closures and Kotlin lambdas are automatically mapped to arguments of that type.
====

In order to provide a way to construct closures while preserving Kotlin's strong typing, two helper methods exist:

* `closureOf<T> {}`
* `delegateClosureOf<T> {}`

Both methods are useful in different circumstances and depend upon the method you are passing the `Closure` instance into.

Some plugins expect simple closures, as with the link:{plugin-portal}plugin/com.jfrog.bintray[Bintray] plugin:

.Use `closureOf<T> {}`
====
include::sample[dir="snippets/kotlinDsl/interoperability-closure-of/kotlin",files="build.gradle.kts[tags=closureOf]"]
====

In other cases, like with the link:{plugin-portal}plugin/org.gretty[Gretty Plugin] when configuring farms, the plugin expects a delegate closure:

.Use `delegateClosureOf<T> {}`
====
include::sample[dir="snippets/kotlinDsl/interoperability-delegate-closure-of/kotlin",files="build.gradle.kts[tags=delegateClosureOf]"]
====

There sometimes isn't a good way to tell, from looking at the source code, which version to use.
Usually, if you get a `NullPointerException` with `closureOf<T> {}`, using `delegateClosureOf<T> {}`
will resolve the problem.

These two utility functions are useful for _configuration closures_, but some plugins might expect Groovy closures for other purposes.
The `KotlinClosure0` to `KotlinClosure2` types allows adapting Kotlin functions to Groovy closures with more flexibility.

.Use `KotlinClosureX` types
====
include::sample[dir="snippets/kotlinDsl/interoperability-kotlinClosure/kotlin",files="build.gradle.kts[tags=kotlinClosure]"]
====

=== The Kotlin DSL Groovy Builder

If some plugin makes heavy use of link:https://groovy-lang.org/metaprogramming.html[Groovy metaprogramming], then using it from Kotlin or Java or any statically-compiled language can be very cumbersome.

The Kotlin DSL provides a `withGroovyBuilder {}` utility extension that attaches the Groovy metaprogramming semantics to objects of type `Any`.
The following example demonstrates several features of the method on the object `target`:

.Use `withGroovyBuilder {}`
====
include::sample[dir="snippets/kotlinDsl/interoperability-groovy-builder/kotlin",files="build.gradle.kts[tags=withGroovyBuilder]"]
====
<1> The receiver is a link:https://docs.groovy-lang.org/latest/html/api/groovy/lang/GroovyObject.html[GroovyObject] and provides Kotlin helpers
<2> The `GroovyObject` API is available
<3> Invoke the `methodName` method, passing some parameters
<4> Configure the `blockName` property, maps to a `Closure` taking method invocation
<5> Invoke `another` method taking named arguments, maps to a Groovy named arguments `Map<String, ?>` taking method invocation

[[using_a_groovy_script]]
=== Using a Groovy script

Another option when dealing with problematic plugins that assume a Groovy DSL build script is to configure them in a Groovy DSL build script that is applied from the main Kotlin DSL build script:

.Using a Groovy script
====
[.multi-language-sample]
=====
.build.gradle.kts
[source, kotlin]
----
plugins {
    id("dynamic-groovy-plugin") version "1.0"               <1>
}
apply(from = "dynamic-groovy-plugin-configuration.gradle")  <2>
----
=====
====

====
[.multi-language-sample]
=====
.dynamic-groovy-plugin-configuration.gradle
[source, groovy]
----
native {                                                    <3>
    dynamic {
        groovy as Usual
    }
}
----
=====
====
<1> The Kotlin build script requests and applies the plugin
<2> The Kotlin build script applies the Groovy script
<3> The Groovy script uses dynamic Groovy to configure plugin

[[kotdsl:limitations]]
== Limitations

* The Kotlin DSL is link:{gradle-issues}15886[known to be slower than the Groovy DSL] on first use, for example with clean checkouts or on ephemeral continuous integration agents.
Changing something in the _buildSrc_ directory also has an impact as it invalidates build-script caching.
The main reason for this is the slower script compilation for Kotlin DSL.
* In IntelliJ IDEA, you must link:https://www.jetbrains.com/help/idea/gradle.html#gradle_import[import your project from the Gradle model] in order to get content assist and refactoring support for your Kotlin DSL build scripts.
* The Kotlin DSL will not support the `model {}` block, which is part of the link:https://blog.gradle.org/state-and-future-of-the-gradle-software-model[discontinued Gradle Software Model].
* We recommend against enabling the incubating <<multi_project_configuration_and_execution#sec:configuration_on_demand,configuration on demand>> feature as it can lead to very hard-to-diagnose problems.

If you run into trouble or discover a suspected bug, please report the issue in the link:{gradle-issues}[Gradle issue tracker].
