// Copyright (C) 2024 Gradle, Inc.
//
// Licensed under the Creative Commons Attribution-Noncommercial-ShareAlike 4.0 International License.;
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      https://creativecommons.org/licenses/by-nc-sa/4.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.

[[implementing_binary_plugins]]
= Binary Plugins
:keywords: binary, plugin

*Binary plugins* refer to plugins that are compiled and distributed as JAR files.
These plugins are usually written in Java or Kotlin and provide custom functionality or tasks to a Gradle build.

[[plugin_anatomy]]
== Anatomy of a binary plugin

A typical Gradle plugin is composed of three cooperating parts:

[cols="1,2,2", options="header"]
|===
| Part | Purpose | Notes

| Plugin class
| Applies behavior to a target (`Project/Settings`), registers tasks, and wires defaults.
| Implements `Plugin<Project>` (or `Plugin<Settings>`). Keeps configuration lazy; avoid doing work in apply.

| Extension
| Holds user configuration exposed as a DSL block.
| Use `Property<T>`, `RegularFileProperty`, `DirectoryProperty`, and `ListProperty<T>` for laziness, validation, and Configuration Cache compatibility.

| Task type
| Implements the actual work when executed.
| Model inputs/outputs with `@Input`, `@InputFile`, `@OutputFile`, etc., to enable incremental builds and caching.
|===

image::plugin_anatomy.png[]

[[example_of_a_binary_plugin]]
== Example of a binary plugin

Here's a detailed look at the project structure for a simple `Greeting` plugin:

====
[.multi-language-sample]
=====
.build.gradle.kts
[source,kotlin]
----
plugin/     // <1>
├── build.gradle.kts    // <2>
└── src/
    └── main/
        └── kotlin/
            └── org/
                └── example/    // <3>
                    ├── GreetingPlugin.kt
                    ├── GreetingPluginExtension.kt
                    └── GreetingTask.kt
----
<1> *`plugin/`*: This is the root directory for the Gradle plugin project.
<2> *`build.gradle.kts`*: The build script for the plugin itself. It specifies dependencies like the Gradle API and Kotlin, and it's where you apply the `kotlin-dsl` or `java-gradle-plugin` to make your code a runnable Gradle plugin.
<3> *`src/main/kotlin/org/example/`*: This is the standard source directory for Kotlin code, organized by package name.
=====
[.multi-language-sample]
=====
.build.gradle
[source,groovy]
----
plugin/     // <1>
├── build.gradle    // <2>
└── src/
    └── main/
        └── groovy/
            └── org/
                └── example/    // <3>
                    ├── GreetingPlugin.groovy
                    ├── GreetingPluginExtension.groovy
                    └── GreetingTask.groovy
----
<1> *`plugin/`*: This is the root directory for the Gradle plugin project.
<2> *`build.gradle`*: The build script for the plugin itself. It specifies dependencies like the Gradle API and Groovy, and it's where you apply the `groovy-gradle-plugin` or `java-gradle-plugin` to make your code a runnable Gradle plugin.
<3> *`src/main/groovy/org/example/`*: This is the standard source directory for Groovy code, organized by package name.
=====
====

[[the_plugin_class]]
=== The plugin class (`GreetingPlugin.kt`)

The core of the plugin is the `GreetingPlugin` class.
It implements the `Plugin<Project>` interface and overrides the `apply` method, which is the entry point for your plugin's logic:

====
include::sample[dir="snippets/reference/plugin-development/plugin-binary/kotlin",files="plugin/src/main/kotlin/org/example/GreetingPlugin.kt[]"]
include::sample[dir="snippets/reference/plugin-development/plugin-binary/groovy",files="plugin/src/main/groovy/org/example/GreetingPlugin.groovy[]"]
====
<1> `project.extensions.create()`: This creates an extension named greeting. This is how users of your plugin can configure its behavior in their build.gradle file. The apply block sets convention values, which are default values that the user can override.
<2> `project.tasks.register()`: This registers a task of type GreetTask named greet. This is the action that your plugin provides.

*Lazy Wiring*: The `message.set(ext.message)` and `outputFile.set(ext.outputFile)` lines are examples of lazy wiring.
The task's inputs are not read immediately.
Instead, they are connected to the extension's properties, and the values are only resolved when the task actually runs.
This is crucial for performance and correctness in Gradle builds.

[[the_extension]]
=== The extension (`GreetingExtension.kt`)

The extension defines the properties that a user can configure.
It uses `Property` and `RegularFileProperty` types, which are designed for lazy evaluation:

====
include::sample[dir="snippets/reference/plugin-development/plugin-binary/kotlin",files="plugin/src/main/kotlin/org/example/GreetingExtension.kt[]"]
include::sample[dir="snippets/reference/plugin-development/plugin-binary/groovy",files="plugin/src/main/groovy/org/example/GreetingExtension.groovy[]"]
====
<1> `Property<T>`: This is a container for a value of type T. The actual value is not read until it's needed, which enables lazy configuration.
<2> `RegularFileProperty`: A specific type of property for file paths. Gradle uses this to track file inputs and outputs for up-to-date checks and the build cache.

[[the_custom_task]]
=== The custom task (`GreetTask.kt`)

This is the class for the custom task.
It defines the inputs and outputs, and the action to perform:

====
include::sample[dir="snippets/reference/plugin-development/plugin-binary/kotlin",files="plugin/src/main/kotlin/org/example/GreetTask.kt[]"]
include::sample[dir="snippets/reference/plugin-development/plugin-binary/groovy",files="plugin/src/main/groovy/org/example/GreetTask.groovy[]"]
====
<1> `@Input`: This annotation marks a property as a task input. When a task has an input, Gradle will automatically track its value. If the value changes between builds, Gradle knows the task is out-of-date and needs to be re-run.
<2> `@OutputFile`: This annotation marks a property as a task output. Gradle tracks the location of this file. If the file is missing or its contents are older than the inputs, Gradle considers the task out-of-date.
<3> `@TaskAction`: This annotation marks the method that contains the work to be done. This method is executed when the task runs.

*Up-to-Date Checks*: By properly annotating inputs and outputs, Gradle can perform up-to-date checks.
If the task's inputs and outputs haven't changed since the last build, Gradle can skip the task entirely, which dramatically speeds up the build process.

[[applying_the_plugin]]
=== Applying the plugin

To use this `Greeting` plugin, you need to apply the plugin in your `build.gradle(.kts)` file.
This makes the plugin's tasks and extensions available to your project:

[source,text]
----
plugins {
    id("org.example.greeting")
}
----

[[configuring_the_plugin]]
=== Configuring the plugin

Once the plugin is applied, you can configure it using the extension you defined, which is named `greeting`.
This allows you to override the default values set in the `GreetingPlugin`.
Using the `greeting` extension block:

[source,text]
----
greeting {
    // Override the default message
    message = "Hola from my custom build"
    // Set a custom output file path
    outputFile = layout.buildDirectory.file("custom-greeting.txt")
}
----

[[running_the_task]]
=== Running the task

The plugin registers a task named `greet`.
After applying and configuring the plugin, you can execute this task from the command line.

[source,bash]
----
$ ./gradlew greet
----

Running the `greet` task will:

- Use the `message` and `outputFile` properties, either with their default values or your custom configured values.
- Write the specified message to the output file (e.g., `build/custom-greeting.txt`).
- Print a log message to the console confirming the file has been written.

[[plugin-development-plugin]]
== Using the Plugin Development plugin

The <<java_gradle_plugin.adoc#java_gradle_plugin,Gradle Plugin Development plugin>> can be used to assist in developing Gradle plugins.

This plugin will automatically apply the <<java_plugin.adoc#java_plugin,Java Plugin>>, add the `gradleApi()` dependency to the `api` configuration, generate the required plugin descriptors in the resulting JAR file, and configure the <<plugins_intermediate.adoc#sec:plugin_markers,Plugin Marker Artifact>> to be used when publishing.

To apply and configure the plugin, add the following code to your build file:

====
include::sample[dir="snippets/reference/plugin-development/customPlugin/kotlin/java-gradle-plugin",files="build.gradle.kts[tags=use-and-configure-plugin]"]
include::sample[dir="snippets/reference/plugin-development/customPlugin/groovy/java-gradle-plugin",files="build.gradle[tags=use-and-configure-plugin]"]
====

Writing and using <<more_about_tasks.adoc#sec:task_groups,custom task types>> is recommended when developing plugins as it automatically benefits from <<incremental_build.adoc#incremental_build,incremental builds>>.
As an added benefit of applying the plugin to your project, the task `validatePlugins` automatically checks for an existing input/output annotation for every public property defined in a custom task type implementation.

[[sec:creating_a_plugin_id]]
== Creating a plugin ID

Plugin IDs are meant to be globally unique, similar to Java package names (i.e., a reverse domain name).
This format helps prevent naming collisions and allows grouping plugins with similar ownership.

An explicit plugin identifier simplifies applying the plugin to a project.
Your plugin ID should combine components that reflect the namespace (a reasonable pointer to you or your organization) and the name of the plugin it provides.
For example, if your Github account is named `foo` and your plugin is named `bar`, a suitable plugin ID might be `com.github.foo.bar`.
Similarly, if the plugin was developed at the `baz` organization, the plugin ID might be `org.baz.bar`.

Plugin IDs should adhere to the following guidelines:

- May contain any alphanumeric character, '.', and '-'.
- Must contain at least one '.' character separating the namespace from the plugin's name.
- Conventionally use a lowercase reverse domain name convention for the namespace.
- Conventionally use only lowercase characters in the name.
- `org.gradle`, `com.gradle`, and `com.gradleware` namespaces may not be used.
- Cannot start or end with a '.' character.
- Cannot contain consecutive '.' characters (i.e., '..').

A namespace that identifies ownership and a name is sufficient for a plugin ID.

When bundling multiple plugins in a single JAR artifact, adhering to the same naming conventions is recommended.
This practice helps logically group related plugins.

There is no limit to the number of plugins that can be defined and registered (by different identifiers) within a single project.

The identifiers for plugins written as a class should be defined in the project's build script containing the plugin classes.
For this, the `java-gradle-plugin` needs to be applied:

====
include::sample[dir="snippets/reference/plugin-development/pluginIdentifier/kotlin",files="buildSrc/build.gradle.kts[]"]
include::sample[dir="snippets/reference/plugin-development/pluginIdentifier/groovy",files="buildSrc/build.gradle[]"]
====

[[sec:working_with_files_in_custom_tasks_and_plugins]]
== Working with files

When developing plugins, it's a good idea to be flexible when accepting input configuration for file locations.

It is recommended to use Gradle's <<properties_providers.adoc#managed_properties,managed properties>> and `project.layout` to select file or directory locations.
This will enable lazy configuration so that the actual location will only be resolved when the file is needed and can be reconfigured at any time during build configuration.

This Gradle build file defines a task `GreetingToFileTask` that writes a greeting to a file.
It also registers two tasks: `greet`, which creates the file with the greeting, and `sayGreeting`, which prints the file's contents.
The `greetingFile` property is used to specify the file path for the greeting:

====
include::sample[dir="snippets/reference/plugin-development/customTaskWithFileProperty/kotlin",files="build.gradle.kts[tags=all]"]
include::sample[dir="snippets/reference/plugin-development/customTaskWithFileProperty/groovy",files="build.gradle[tags=all]"]
====

[source,bash]
----
$ ./gradlew -q sayGreeting
----
[source,text]
----
include::{snippetsPath}/reference/plugin-development/customTaskWithFileProperty/tests/lazyFileProperties.out[]
----

In this example, we configure the `greet` task `destination` property as a closure/provider, which is evaluated with
the link:{groovyDslPath}/org.gradle.api.Project.html#org.gradle.api.Project:file(java.lang.Object)[Project.file(java.lang.Object)] method to turn the return value of the closure/provider into a `File` object at the last minute.
Note that we specify the `greetingFile` property value _after_ the task configuration.
This lazy evaluation is a key benefit of accepting any value when setting a file property and then resolving that value when reading the property.

You can learn more about working with files lazily in <<working_with_files.adoc#working_with_files,Working with Files>>.

[[capturing_user_input_to_configure_plugin_runtime_behavior]]
== Making a plugin configurable using extensions

Most plugins offer configuration options for build scripts and other plugins to customize how the plugin works.
Plugins do this using *extension objects*.

A link:{groovyDslPath}/org.gradle.api.Project.html[Project] has an associated link:{javadocPath}/org/gradle/api/plugins/ExtensionContainer.html[ExtensionContainer] object that contains all the settings and properties for the plugins that have been applied to the project.
You can provide configuration for your plugin by adding an extension object to this container.

An extension object is simply an object with Java Bean properties representing the configuration.

Let's add a `greeting` extension object to the project, which allows you to configure the greeting:

====
include::sample[dir="snippets/reference/plugin-development/customPluginNoConvention/kotlin",files="build.gradle.kts[]"]
include::sample[dir="snippets/reference/plugin-development/customPluginNoConvention/groovy",files="build.gradle[]"]
====

[source,bash]
----
$ ./gradlew -q hello
----
[source,text]
----
include::{snippetsPath}/reference/plugin-development/customPluginNoConvention/tests/customPluginNoConvention.out[]
----

In this example, `GreetingPluginExtension` is an object with a property called `message`.
The extension object is added to the project with the name `greeting`.
This object becomes available as a project property with the same name as the extension object.
`the<GreetingPluginExtension>()` is equivalent to `project.extensions.getByType(GreetingPluginExtension::class.java)`.

Often, you have several related properties you need to specify on a single plugin.
Gradle adds a configuration block for each extension object, so you can group settings:

====
include::sample[dir="snippets/reference/plugin-development/customPluginWithAdvancedConvention/kotlin",files="build.gradle.kts[]"]
include::sample[dir="snippets/reference/plugin-development/customPluginWithAdvancedConvention/groovy",files="build.gradle[]"]
====

[source,bash]
----
$ ./gradlew -q hello
----
[source,text]
----
include::{snippetsPath}/reference/plugin-development/customPluginWithAdvancedConvention/tests/customPluginWithAdvancedConvention.out[]
----

[.multi-language-text.lang-kotlin]
In this example, several settings can be grouped within the `configure<GreetingPluginExtension>` block.
The link:{javadocPath}/org/gradle/api/Project.html#configure-java.lang.Object-groovy.lang.Closure-[`configure`] function is used to configure an extension object.
It provides a convenient way to set properties or apply configurations to these objects.
The type used in the build script's `configure` function (`GreetingPluginExtension`) must match the extension type.
Then, when the block is executed, the receiver of the block is the extension.

[.multi-language-text.lang-groovy]
In this example, several settings can be grouped within the `greeting` closure. The name of the closure block in the build script (`greeting`) must match the extension object name.
Then, when the closure is executed, the fields on the extension object will be mapped to the variables within the closure based on the standard Groovy closure delegate feature.

[[sec:declaring_a_dsl_configuration_container]]
[[declaring_a_dsl_configuration_container]]
== Declaring a DSL configuration container

Using an extension object _extends_ the Gradle DSL to add a project property and DSL block for the plugin.
Because an extension object is a regular object, you can provide your own DSL nested inside the plugin block by adding properties and methods to the extension object.

Let's consider the following build script for illustration purposes.

====
include::sample[dir="snippets/reference/plugin-development/namedDomainObjectContainer/kotlin",files="build.gradle.kts[]"]
include::sample[dir="snippets/reference/plugin-development/namedDomainObjectContainer/groovy",files="build.gradle[]"]
====

The DSL exposed by the plugin exposes a container for defining a set of environments.
Each environment the user configures has an arbitrary but declarative name and is represented with its own DSL configuration block.
The example above instantiates a development, staging, and production environment, including its respective URL.

Each environment must have a data representation in code to capture the values.
The name of an environment is immutable and can be passed in as a constructor parameter.
Currently, the only other parameter the data object stores is a URL.

The following `ServerEnvironment` object fulfills those requirements:

.ServerEnvironment.java
[source,java]
----
include::{snippetsPath}/reference/plugin-development/namedDomainObjectContainer/common/buildSrc/src/main/java/org/myorg/ServerEnvironment.java[tags=snippet]
----

Gradle exposes the factory method
link:{javadocPath}/org/gradle/api/model/ObjectFactory.html#domainObjectContainer-java.lang.Class-org.gradle.api.NamedDomainObjectFactory-[ObjectFactory.domainObjectContainer(Class, NamedDomainObjectFactory)]
to create a container of data objects.
The parameter the method takes is the class representing the data.
The created instance of type link:{javadocPath}/org/gradle/api/NamedDomainObjectContainer.html[NamedDomainObjectContainer] can be exposed to the end user by adding it to the extension container with a specific name.

It's common for a plugin to post-process the captured values within the plugin implementation, e.g., to configure tasks:

.ServerEnvironmentPlugin.java
[source,java]
----
include::{snippetsPath}/reference/plugin-development/namedDomainObjectContainer/common/buildSrc/src/main/java/org/myorg/ServerEnvironmentPlugin.java[tags=snippet]
----

In the example above, a deployment task is created dynamically for every user-configured environment.

You can find out more about implementing project extensions in <<properties_providers.adoc#properties_and_providers,Developing Custom Gradle Types>>.

[[modeling_dsl_like_apis]]
== Modeling DSL-like APIs

DSLs exposed by plugins should be readable and easy to understand.

For example, let's consider the following extension provided by a plugin.
In its current form, it offers a "flat" list of properties for configuring the creation of a website:

====
include::sample[dir="snippets/reference/plugin-development/pluginExtension/kotlin",files="build-flat.gradle.kts[]"]
include::sample[dir="snippets/reference/plugin-development/pluginExtension/groovy",files="build-flat.gradle[]"]
====

As the number of exposed properties grows, you should introduce a nested, more expressive structure.

The following code snippet adds a new configuration block named `siteInfo` as part of the extension.
This provides a stronger indication of what those properties mean:

====
include::sample[dir="snippets/reference/plugin-development/pluginExtension/kotlin",files="build.gradle.kts[]"]
include::sample[dir="snippets/reference/plugin-development/pluginExtension/groovy",files="build.gradle[]"]
====

Implementing the backing objects for such an extension is simple.
First, introduce a new data object for managing the properties `websiteUrl` and `vcsUrl`:

.SiteInfo.java
[source,java]
----
include::{snippetsPath}/reference/plugin-development/pluginExtension/common/buildSrc/src/main/java/org/myorg/SiteInfo.java[tags=snippet]
----

In the extension, create an instance of the `siteInfo` class and a method to delegate the captured values to the data instance.

To configure underlying data objects, define a parameter of type link:{javadocPath}/org/gradle/api/Action.html[Action].

The following example demonstrates the use of `Action` in an extension definition:

.SiteExtension.java
[source,java]
----
include::{snippetsPath}/reference/plugin-development/pluginExtension/common/buildSrc/src/main/java/org/myorg/SiteExtension.java[tags=snippet]
----

[[sec:mapping_extension_properties_to_task_properties_in_binary_plugins]]
== Mapping extension properties to task properties

Plugins commonly use an extension to capture user input from the build script and map it to a custom task's input/output properties.
The build script author interacts with the extension's DSL, while the plugin implementation handles the underlying logic:

====
include::sample[dir="snippets/reference/plugin-development/mappingExtensions/kotlin",files="app/build.gradle.kts[tags=snippet]"]
include::sample[dir="snippets/reference/plugin-development/mappingExtensions/groovy",files="app/build.gradle[tags=snippet]"]
====

In this example, the `MyExtension` class defines an `inputParameter` property that can be set in the build script.
The `MyPlugin` class configures this extension and uses its `inputParameter` value to configure the `MyCustomTask` task.
The `MyCustomTask` task then uses this input parameter in its logic.

You can learn more about types you can use in task implementations and extensions in <<lazy_configuration.adoc#lazy_configuration,Lazy Configuration>>.

[[sec:plugin_conventions_in_binary_plugins]]
== Adding default configuration with conventions

Plugins should provide sensible defaults and standards in a specific context, reducing the number of decisions users need to make.
Using the `project` object, you can define default values.
These are known as *conventions*.

Conventions are properties that are initialized with default values and can be overridden by the user in their build script.
For example:

====
include::sample[dir="snippets/reference/plugin-development/customPluginWithConvention/kotlin",files="build.gradle.kts[]"]
include::sample[dir="snippets/reference/plugin-development/customPluginWithConvention/groovy",files="build.gradle[]"]
====

[source,bash]
----
$ ./gradlew -q hello
----
[source,text]
----
include::{snippetsPath}/reference/plugin-development/customPluginWithConvention/tests/customPluginWithConvention.out[]
----

In this example, `GreetingPluginExtension` is a class that represents the convention.
The message property is the convention property with a default value of 'Hello from GreetingPlugin'.

Users can override this value in their build script:

====
[.multi-language-sample]
=====
.build.gradle.kts
[source,kotlin]
----
GreetingPluginExtension {
    message = "Custom message"
}
----
=====
[.multi-language-sample]
=====
.build.gradle
[source,groovy]
----
GreetingPluginExtension {
    message = 'Custom message'
}
----
=====
====

[source,bash]
----
$ ./gradlew -q hello
----
[source,text]
----
Custom message
----

[[capabilities-vs-conventions]]
== Separating capabilities from conventions

Separating capabilities from conventions in plugins allows users to choose which tasks and conventions to apply.

For example, the Java Base plugin provides un-opinionated (i.e., generic) functionality like `SourceSets`, while the Java plugin adds tasks and conventions familiar to Java developers like `classes`, `jar` or `javadoc`.

When designing your own plugins, consider developing two plugins — one for capabilities and another for conventions — to offer flexibility to users.

In the example below, `MyPlugin` contains conventions, and `MyBasePlugin` defines capabilities.
Then, `MyPlugin` applies `MyBasePlugin`, this is called _plugin composition_.
To apply a plugin from another one:

.MyBasePlugin.java
[source,java]
----
include::{snippetsPath}/reference/plugin-development/capabilitiesVsConventions/groovy/buildSrc/src/main/java/MyBasePlugin.java[]
----

.MyPlugin.java
[source,java]
----
include::{snippetsPath}/reference/plugin-development/capabilitiesVsConventions/groovy/buildSrc/src/main/java/MyPlugin.java[]
----

[[sec:reacting_to_plugins]]
[[reacting_to_plugins]]
== Reacting to plugins

A common pattern in Gradle plugin implementations is configuring the runtime behavior of existing plugins and tasks in a build.

For example, a plugin could assume that it is applied to a Java-based project and automatically reconfigure the standard source directory:

[[convention-api-usage-example]]
.InhouseStrongOpinionConventionJavaPlugin.java
[source,java]
----
include::{snippetsPath}/reference/plugin-development/reactingToPlugins/groovy/buildSrc/src/main/java/InhouseStrongOpinionConventionJavaPlugin.java[tags=snippet]
----

The drawback to this approach is that it automatically forces the project to apply the Java plugin, imposing a strong opinion on it (i.e., reducing flexibility and generality).
In practice, the project applying the plugin might not even deal with Java code.

Instead of automatically applying the Java plugin, the plugin could react to the fact that the consuming project applies the Java plugin.
Only if that is the case, then a certain configuration is applied:

.InhouseConventionJavaPlugin.java
[source,java]
----
include::{snippetsPath}/reference/plugin-development/reactingToPlugins/groovy/buildSrc/src/main/java/InhouseConventionJavaPlugin.java[tags=snippet]
----

Reacting to plugins is preferred over applying plugins if there is no good reason to assume that the consuming project has the expected setup.

The same concept applies to task types:

.InhouseConventionWarPlugin.java
[source,java]
----
include::{snippetsPath}/reference/plugin-development/reactingToPlugins/groovy/buildSrc/src/main/java/InhouseConventionWarPlugin.java[tags=snippet]
----

[[sec:reacting_to_build_features]]
[[reacting_to_build_features]]
== Reacting to build features

Plugins can access the status of build features in the build.
The link:{javadocPath}/org/gradle/api/configuration/BuildFeatures.html[Build Features API] allows checking whether the user requested a particular Gradle feature and if it is active in the current build.
An example of a build feature is the <<configuration_cache.adoc#config_cache,configuration cache>>.

There are two main use cases:

- Using the status of build features in reports or statistics.
- Incrementally adopting experimental Gradle features by disabling incompatible plugin functionality.

Below is an example of a plugin that utilizes both of the cases.

.Reacting to build features
[source,java]
----
include::{snippetsPath}/reference/plugin-development/reactingToBuildFeatures/groovy/buildSrc/src/main/java/MyPlugin.java[tags=my-plugin]
----
<1> The `BuildFeatures` service can be injected into plugins, tasks, and other managed types.
<2> Accessing the `requested` status of a feature for reporting.
<3> Using the `active` status of a feature to disable incompatible functionality.

[WARNING]
====
Disabling functionality based on a feature's `active` status makes the plugin behave differently depending on whether the feature is enabled, which raises complexity and can lead to divergent build results.
Treat such conditionals as a last resort, and prefer making the functionality compatible with the feature instead.
For the <<isolated_projects.adoc#isolated_projects,Isolated Projects>> feature specifically, see <<isolated_projects.adoc#sec:guarding_build_logic,Guard incompatible build logic as a last resort>>.
====

[[build_feature_properties]]
=== Build feature properties

A `BuildFeature` status properties are represented with `Provider<Boolean>` types.

The link:{javadocPath}/org/gradle/api/configuration/BuildFeature.html#getRequested--[`BuildFeature.getRequested()`] status of a build feature determines if the user requested to enable or disable the feature.

When the `requested` provider value is:

- `true` -- the user opted in for using the feature
- `false` -- the user opted out from using the feature
- `undefined` -- the user neither opted in nor opted out from using the feature

The link:{javadocPath}/org/gradle/api/configuration/BuildFeature.html#getActive--[`BuildFeature.getActive()`] status of a build feature is always defined.
It represents the effective state of the feature in the build.

When the `active` provider value is:

- `true` -- the feature _may_ affect the build behavior in a way specific to the feature
- `false` -- the feature will not affect the build behavior

Note that the `active` status does not depend on the `requested` status.
Even if the user requests a feature, it may still not be active due to other build options being used in the build.
Gradle can also activate a feature by default, even if the user did not specify a preference.

[[custom_dependencies_blocks]]
== Using a custom `dependencies` block

A plugin can provide dependency declarations in custom blocks that allow users to declare dependencies in a type-safe and context-aware way.

For instance, instead of users needing to know and use the underlying `Configuration` name to add dependencies, a custom `dependencies` block lets the plugin pick a meaningful name that
can be used consistently.

[[adding_a_custom_dependencies_block]]
=== Adding a custom `dependencies` block

To add a custom `dependencies` block, you need to create a new <<properties_providers.adoc#properties_and_providers,type>> that will represent the set of dependency scopes available to users.
That new type needs to be accessible from a part of your plugin (from a domain object or extension).
Finally, the dependency scopes need to be wired back to underlying `Configuration` objects that will be used during dependency resolution.

See link:{groovyDslPath}/org.gradle.api.plugins.jvm.JvmComponentDependencies.html[JvmComponentDependencies] and link:{groovyDslPath}/org.gradle.api.plugins.jvm.JvmTestSuite.html[JvmTestSuite] for an example of how this is used in a Gradle core plugin.

[[create_an_interface_that_extends_dependencies]]
==== 1. Create an interface that extends `Dependencies`

NOTE: You can also extend link:{groovyDslPath}/org.gradle.api.artifacts.dsl.GradleDependencies.html[GradleDependencies] to get access to Gradle-provided dependencies like `gradleApi()`.

====
[source.multi-language-sample,java]
.ExampleDependencies.java
----
include::{snippetsPath}/reference/plugin-development/dependenciesBlock/common/buildSrc/src/main/java/com/example/ExampleDependencies.java[tags=custom-dependencies-type]
----
====

[[add_accessors_for_dependency_scopes]]
==== 2. Add accessors for dependency scopes

For each dependency scope your plugin wants to support, add a getter method that returns a `DependencyCollector`.

====
[source.multi-language-sample,java]
.ExampleDependencies.java
----
include::{snippetsPath}/reference/plugin-development/dependenciesBlock/common/buildSrc/src/main/java/com/example/ExampleDependencies.java[tags=custom-dependencies-scopes]
----
====

[[add_accessors_for_custom_dependencies_block]]
==== 3. Add accessors for custom `dependencies` block

To make the custom `dependencies` block configurable, the plugin needs to add a `getDependencies` method that returns the new type from above and a configurable block method named `dependencies`.

By convention, the accessors for your custom `dependencies` block should be called `getDependencies()`/`dependencies(Action)`.
This method could be named something else, but users would need to know that a different block can behave like a `dependencies` block.

====
[source.multi-language-sample,java]
.ExampleExtension.java
----
include::{snippetsPath}/reference/plugin-development/dependenciesBlock/common/buildSrc/src/main/java/com/example/ExampleExtension.java[tags=dependencies-accessors]
----
====

[[wire_dependency_scope_to_configuration]]
==== 4. Wire dependency scope to `Configuration`

Finally, the plugin needs to wire the custom `dependencies` block to some underlying `Configuration` objects. If this is not done, none of the dependencies declared in the custom block will
be available to dependency resolution.

====
[source.multi-language-sample,java]
.ExamplePlugin.java
----
include::{snippetsPath}/reference/plugin-development/dependenciesBlock/common/buildSrc/src/main/java/com/example/ExamplePlugin.java[tags=wire-dependencies]
----
====

NOTE: In this example, the name users will use to add dependencies is "implementation", but the underlying `Configuration` is named `exampleImplementation`.

====
[source.multi-language-sample,kotlin]
.build.gradle.kts
----
include::{snippetsPath}/reference/plugin-development/dependenciesBlock/kotlin/build.gradle.kts[tags=dependencies]
----
[source.multi-language-sample,groovy]
.build.gradle
----
include::{snippetsPath}/reference/plugin-development/dependenciesBlock/groovy/build.gradle[tags=dependencies]
----
====

[[sec:differences_with_top_level_dependencies_plugins]]
=== Differences between the custom `dependencies` and the top-level `dependencies` blocks

Each dependency scope returns a link:{groovyDslPath}/org.gradle.api.artifacts.dsl.DependencyCollector.html[`DependencyCollector`] that provides strongly-typed methods to add and configure dependencies.

There is also a link:{javadocPath}/org/gradle/api/artifacts/dsl/DependencyFactory.html[`DependencyFactory`] with factory methods to create new dependencies from different notations.
Dependencies can be created lazily using these factory methods, as shown below.

A custom `dependencies` block differs from the top-level `dependencies` block in the following ways:

* Dependencies must be declared using a `String`, an instance of `Dependency`, a `FileCollection`, a `Provider` of `Dependency`, or a `ProviderConvertible` of `MinimalExternalModuleDependency`.
* Outside of Gradle build scripts, you must explicitly call a getter for the `DependencyCollector` and `add`.
** `dependencies.add("implementation", x)` becomes `getImplementation().add(x)`
* You cannot add a dependency with an instance of `Project`. You must turn it into a `ProjectDependency` first.
* You cannot add version catalog bundles directly.
Instead, use the `bundle` method on each configuration.
** Kotlin and Groovy: `implementation(libs.bundles.testing)` becomes `implementation.bundle(libs.bundles.testing)`
* You cannot use providers for non-`Dependency` types directly.
Instead, map them to a `Dependency` using the `DependencyFactory`.
** Kotlin and Groovy: `implementation(myStringProvider)` becomes `implementation(myStringProvider.map { dependencyFactory.create(it) })`
** Java: `implementation(myStringProvider)` becomes `getImplementation().add(myStringProvider.map(getDependencyFactory()::create)`
* Unlike the top-level `dependencies` block, constraints are not in a separate block.
** Instead, constraints are added by decorating a dependency with `constraint(...)` like `implementation(constraint("org:foo:1.0"))`.

Keep in mind that the `dependencies` block may not provide access to the same methods as the link:{groovyDslPath}/org.gradle.api.artifacts.dsl.DependencyHandler.html[top-level `dependencies` block].

NOTE: Plugins should prefer adding dependencies via their own `dependencies` block.

[[sec:providing_default_dependencies]]
[[providing_default_dependencies]]
== Providing default dependencies

The implementation of a plugin sometimes requires the use of an external dependency.

You might want to automatically download an artifact using Gradle’s dependency management mechanism and later use it in the action of a task type declared in the plugin.
Ideally, the plugin implementation does not need to ask the user for the coordinates of that dependency - it can simply predefine a sensible default version.

Let’s look at an example of a plugin that downloads files containing data for further processing.
The plugin implementation declares a custom configuration that allows for <<declaring_dependencies.adoc#one-declaring-dependencies,assigning those external dependencies with dependency coordinates>>:

.DataProcessingPlugin.java
[source,java]
----
include::{snippetsPath}/reference/plugin-development/defaultDependency/common/buildSrc/src/main/java/org/myorg/DataProcessingPlugin.java[tags=snippet]
----

.DataProcessing.java
[source,java]
----
include::{snippetsPath}/reference/plugin-development/defaultDependency/common/buildSrc/src/main/java/org/myorg/DataProcessing.java[tags=snippet]
----

This approach is convenient for the end user as there is no need to actively declare a dependency.
The plugin already provides all the details about this implementation.

But what if the user wants to redefine the default dependency?

No problem.
The plugin also exposes the custom configuration that can be used to assign a different dependency.
Effectively, the default dependency is overwritten:

====
include::sample[dir="snippets/reference/plugin-development/defaultDependency/kotlin",files="build.gradle.kts[]"]
include::sample[dir="snippets/reference/plugin-development/defaultDependency/groovy",files="build.gradle[]"]
====

You will find that this pattern works well for tasks that require an external dependency when the task's action is executed.
You can go further and abstract the version to be used for the external dependency by exposing an extension property (e.g.
`toolVersion` in link:{groovyDslPath}/org.gradle.testing.jacoco.plugins.JacocoPluginExtension.html[the JaCoCo plugin]).

[[minimizing_the_use_of_external_libraries]]
=== Minimizing the use of external libraries

Using external libraries in your Gradle projects can bring great convenience, but be aware that they can introduce complex dependency graphs.
Gradle's `buildEnvironment` task can help you visualize these dependencies, including those of your plugins.
Keep in mind that plugins share the same classloader, so conflicts may arise with different versions of the same library.

To demonstrate let’s assume the following build script:

====
include::sample[dir="snippets/reference/plugin-development/externalLibraries/kotlin",files="build.gradle.kts[]"]
include::sample[dir="snippets/reference/plugin-development/externalLibraries/groovy",files="build.gradle[]"]
====

The output of the task clearly indicates the classpath of the `classpath` configuration:

[source,bash]
----
$ ./gradlew buildEnvironment
----
[source,text]
----
include::{snippetsPath}/reference/plugin-development/externalLibraries/tests/buildEnvironment.out[]
----

A Gradle plugin does not run in its own, isolated classloader, so you must consider whether you truly need a library or if a simpler solution suffices.

For logic that is executed as part of task execution, use the <<worker_api.adoc#tasks_parallel_worker, Worker API>> that allows you to isolate libraries.

[[plugin-with-variants]]
== Providing multiple variants of a plugin

Variants of a plugin refer to different flavors or configurations of the plugin that are tailored to specific needs or use cases.
These variants can include different implementations, extensions, or configurations of the base plugin.

The most convenient way to configure additional plugin variants is to use <<how_to_create_feature_variants_of_a_library#feature_variants,feature variants>>, a concept available in all Gradle projects that apply one of the Java plugins:

[source,kotlin]
----
dependencies {
    implementation 'com.google.guava:guava:30.1-jre'        // Regular dependency
    featureVariant 'com.google.guava:guava-gwt:30.1-jre'    // Feature variant dependency
}
----

In the following example, each plugin variant is developed in isolation.
A separate source set is compiled and packaged in a separate jar for each variant.

The following sample demonstrates how to add a variant that is compatible with Gradle 7.0+ while the "main" variant is compatible with older versions:

====
include::sample[dir="snippets/reference/plugin-development/pluginWithVariants/kotlin",files="build.gradle.kts[tags=add-plugin-variant]"]
include::sample[dir="snippets/reference/plugin-development/pluginWithVariants/groovy",files="build.gradle[tags=add-plugin-variant]"]
====

NOTE: Only Gradle versions 7 or higher can be explicitly targeted by a variant, as support for this was only added in Gradle 7.

First, we declare a separate _source set_ and a _feature variant_ for our Gradle 7 plugin variant.
Then, we do some specific wiring to turn the feature into a proper Gradle plugin variant:

<1> Assign the <<component_capabilities.adoc#sec:declaring-component-capabilities,implicit capability that corresponds to the components GAV>> to the variant.
<2> Assign the <<variant_attributes.adoc#sec:gradle-plugins-default-attributes,Gradle API version attribute>> to all <<declaring_configurations.adoc#sec:resolvable-consumable-configs,consumable configurations>> of our Gradle7 variant. Gradle uses this information to determine which variant to select during plugin resolution.
<3> Configure the `processGradle7Resources` task to ensure the plugin descriptor file is added to the Gradle7 variant Jar.
<4> Add a dependency to the `gradleApi()` for our new variant so that the API is visible during compilation time.

Note that there is currently no convenient way to access the API of other Gradle versions as the one you are building the plugin with.
Ideally, every variant should be able to declare a dependency on the API of the minimal Gradle version it supports.
This will be improved in the future.

The above snippet assumes that all variants of your plugin have the plugin class at the same location.
That is, if your plugin class is `org.example.GreetingPlugin`, you need to create a second variant of that class in `src/gradle7/java/org/example`.

[[using_version_specific_variants_of_multi_variant_plugins]]
=== Using version-specific variants of multi-variant plugins

Given a dependency on a multi-variant plugin, Gradle will automatically choose its variant that best matches the current Gradle version when it resolves any of:

* plugins specified in the <<plugins_intermediate.adoc#sec:plugins_block,`plugins {}` block>>;
* `buildscript` classpath dependencies;
* dependencies in the root project of the <<sharing_build_logic_between_subprojects.adoc#sec:using_buildsrc,build source (`buildSrc`)>> that appear on the compile or runtime classpath;
* dependencies in a project that applies the <<java_gradle_plugin.adoc#java_gradle_plugin,Java Gradle Plugin Development plugin>> or the <<kotlin_dsl.adoc#sec:kotlin-dsl_plugin,Kotlin DSL plugin>>, appearing on the compile or runtime classpath.

The best matching variant is the variant that targets the highest Gradle API version and does not exceed the current build's Gradle version.

In all other cases, a plugin variant that does not specify the supported Gradle API version is preferred if such a variant is present.

In projects that use plugins as dependencies, requesting the variants of plugin dependencies that support a different Gradle version is possible.
This allows a multi-variant plugin that depends on other plugins to access their APIs, which are exclusively provided in their version-specific variants.

This snippet makes the <<#plugin-with-variants,plugin variant `gradle7` defined above>> consume the matching variants of its dependencies on other multi-variant plugins:

====
include::sample[dir="snippets/reference/plugin-development/pluginWithVariants/kotlin",files="build.gradle.kts[tags=consume-plugin-variant]"]
include::sample[dir="snippets/reference/plugin-development/pluginWithVariants/groovy",files="build.gradle[tags=consume-plugin-variant]"]
====

[[plugin-dependency-conflicts]]
== Avoiding plugin dependency conflicts

When developing a plugin that relies on the API of another plugin (e.g., the Android Gradle Plugin or the Kotlin Plugin), declaring that API dependency using the standard `implementation` configuration can cause serious classpath conflicts for the end user.

When applying your plugin to a project, the dependency you used may spill into the build script classpath of the project's subprojects, potentially overriding a newer version of the dependency required there.

To prevent buildscript classpath leakage and maintain version flexibility for your users, use the `compileOnly` configuration for any dependency that represents an underlying plugin's API.

[source,text]
----
dependencies {
    // BAD: Can spill onto subproject classpaths, potentially overriding their version
    // implementation("com.android.tools.build:gradle-api:8.0.0")

    // GOOD: Only available during compilation; user's project dictates the runtime version
    compileOnly("com.android.tools.build:gradle-api:8.0.0")
}
----

If you need to *enforce* a specific version (e.g., for internal <<implementing_gradle_plugins_convention.adoc#implementing_convention_plugins,Convention Plugins>>), the `implementation` approach may be acceptable, but this should be done with clear awareness of the potential user conflicts.

Because `compileOnly` dependencies are not available at runtime, plugin authors should:

1. **Document** that the plugin requires the other plugin to be explicitly applied by the user.
2. **Implement the plugin defensively** to avoid throwing `NoClassDefFoundError` when the dependency is missing.
Use link:{javadocPath}/org/gradle/api/plugins/PluginManager.html#withPlugin-java.lang.String-org.gradle.api.Action-[`PluginManager.withPlugin(String, Action)`] to guard code that references classes from the `compileOnly` dependency:
+
[source,kotlin]
----
project.pluginManager.withPlugin("com.android.application") {
    // Safe to reference Android plugin classes here
}
----

WARNING: Using the `compileOnly` configuration will cause the standard plugin testing method, `GradleRunner.withPluginClasspath()`, to fail. See <<test_kit.adoc#sub:test-kit-automatic-classpath-injection,Automatic classpath injection with the Plugin Development Plugin>> to learn more.
