Gradle exposes a set of services, covering things like file and archive operations, process execution, dependency creation, worker scheduling, problem reporting, build-feature flags, and dataflow scheduling.

A service is a collaborator object whose lifecycle Gradle manages; a single instance is shared across the build and supplied to your code on demand. These services aren’t meant to be constructed directly, since they rely on internal Gradle state.

To use a service, your custom type declares a dependency on it and Gradle supplies the instance. This pattern is called service injection, and it works uniformly across every type Gradle instantiates for you, including tasks, plugins, extensions, value sources, build services, and worker actions.

The most common form is constructor injection on an abstract type. The same CleanTempTask is shown below as a Kotlin DSL class, a Groovy DSL class, and a stand-alone Java class that you would typically place in buildSrc or a binary plugin:

build.gradle.kts
abstract class CleanTempTask
@Inject constructor(private val fs: FileSystemOperations) : DefaultTask() {

    @TaskAction
    fun run() {
        fs.delete { delete("build/tmp") }
    }
}

tasks.register("cleanTemp", CleanTempTask::class) {}
build.gradle
abstract class CleanTempTask extends DefaultTask {
    private FileSystemOperations fs

    @Inject //@javax.inject.Inject
    CleanTempTask(FileSystemOperations fs) {
        this.fs = fs
    }

    @TaskAction
    void run() {
        fs.delete { spec -> spec.delete("build/tmp") }
    }
}

tasks.register("cleanTemp", CleanTempTask) {}
CleanTempTask.java
public abstract class CleanTempTask extends DefaultTask {
    private final FileSystemOperations fs;

    @Inject
    public CleanTempTask(FileSystemOperations fs) {
        this.fs = fs;
    }

    @TaskAction
    public void run() {
        fs.delete(spec -> spec.delete("build/tmp"));
    }
}

A task that needs to run work in parallel injects the WorkerExecutor service in the same way, as shown in the worker API section.

Reaching for service injection rather than project.copy(…​), project.exec(…​), or other ad-hoc Project accessors helps keep your code compatible with the Configuration Cache and Isolated Projects, and makes your types easier to unit-test by passing stub services. See Service injection patterns for the full set of @Inject forms used in the rest of this page.

Available services

You should avoid injecting types not listed below. Internal services can sometimes technically be injected, but this practice is not supported and may lead to breaking changes in the future. Only inject the services explicitly listed below to ensure stability and compatibility.

The following services are available for injection in all Gradle instantiated objects:

Service Description

ObjectFactory

Creates model objects, properties, collections, and file-related objects. Use it when defining custom Gradle types or nested DSL objects in a plugin or extension.

ProviderFactory

Creates Provider instances and exposes environment, system-property, and Gradle-property values. Use it to read environment variables, system properties, or to wrap a computed value as a lazy Provider.

FileSystemOperations

Runs filesystem operations such as deleting, copying, or syncing files and directories. Use it from a task or worker action that needs to delete, copy, or sync files.

ArchiveOperations

Runs operations on archive files such as ZIP or TAR. Use it to read or extract the contents of an archive.

ExecOperations

Runs external processes, with dedicated support for running external java programs. Use it to run an external program or java process from a task or worker action.

Problems Incubating

Reports structured problems that surface in the console, the HTML problems report, and the Tooling API. Use it to surface errors or warnings consistently to the IDE, the problems report, and Build Scan.

Additional services in workers

The following services are available for injection in worker API actions and parameters:

Service Description

WorkerExecutor

Schedules work to run in parallel via the Worker API. Use it from a task that needs to run CPU-bound work in parallel or in an isolated classloader.

Additional services in projects and settings

The following services are available for injection in both project and settings plugins, extensions and objects:

Service Description

ToolingModelBuilderRegistry

Registers a Gradle Tooling API model builder. Use it to expose a custom model to the Tooling API so IDEs and other tools can consume it.

DependencyFactory

Creates Dependency instances in a type-safe way. Use it to programmatically construct Dependency instances in a plugin without a Project reference.

DependencyConstraintFactory Incubating

Creates DependencyConstraint instances in a type-safe way. Use it to programmatically construct dependency constraints in a plugin without a Project reference.

BuildFeatures

Reports whether features such as Configuration Cache and Isolated Projects are requested and active. Use it to branch plugin logic on whether the Configuration Cache or Isolated Projects is active.

FlowScope and FlowProviders Incubating

Register dataflow actions that run on build lifecycle events such as build completion. Use them to run cleanup, notification, or reporting work at the end of every build.

BuildInvocationDetails Incubating

Exposes information about the current build invocation, such as its wall-clock start time. Use it to read the build’s start time for timing or reporting.

Additional services in projects

The following services are available for injection in project plugins, extensions and objects created in a project:

Service Description

ProjectLayout

Provides access to key project locations such as the project directory and build directory. Use it to resolve paths relative to the project directory or build directory.

WorkerExecutor

Schedules work to run in parallel via the Worker API. Use it from a task that needs to run CPU-bound work in parallel or in an isolated classloader.

TestEventReporterFactory Incubating

Provides access to Gradle’s test event reporting API. Use it to emit test events from a custom task that runs tests itself.

SoftwareComponentFactory

Creates adhoc software components for publishing. Use it to define a custom publishable software component without a full component model.

Additional services in settings

The following services are available for injection in settings plugins, extensions and objects created in a settings script:

Service Description

BuildLayout

Provides access to important locations for a Gradle build, such as the root directory and settings file. Use it from a settings plugin to resolve paths relative to the root settings directory.

ObjectFactory

ObjectFactory is a service for creating custom Gradle types, allowing you to define nested objects and DSLs in your build logic. It provides methods for creating instances of different types, such as properties (Property<T>), collections (ListProperty<T>, SetProperty<T>, MapProperty<K, V>), file-related objects (RegularFileProperty, DirectoryProperty, ConfigurableFileCollection, ConfigurableFileTree), and more.

You can obtain an instance of ObjectFactory using the project.objects property. Here’s a simple example demonstrating how to use ObjectFactory to create a property and set its value:

build.gradle.kts
tasks.register("myObjectFactoryTask") {
    doLast {
        val objectFactory = project.objects
        val myProperty = objectFactory.property(String::class)
        myProperty.set("Hello, Gradle!")
        println(myProperty.get())
    }
}
build.gradle
tasks.register("myObjectFactoryTask") {
    doLast {
        def objectFactory = project.objects
        def myProperty = objectFactory.property(String)
        myProperty.set("Hello, Gradle!")
        println myProperty.get()
    }
}
It is preferable to let Gradle create objects automatically by using managed properties.

Using ObjectFactory to create these objects ensures that they are properly managed by Gradle, especially in terms of configuration avoidance and lazy evaluation. This means that the values of these objects are only calculated when needed, which can improve build performance.

In the following example, a project extension called DownloadExtension receives an ObjectFactory instance through its constructor. The constructor uses this to create a nested Resource object (also a custom Gradle type) and makes this object available through the resource property:

DownloadExtension.java
public class DownloadExtension {
    // A nested instance
    private final Resource resource;

    @Inject
    public DownloadExtension(ObjectFactory objectFactory) {
        // Use an injected ObjectFactory to create a Resource object
        resource = objectFactory.newInstance(Resource.class);
    }

    public Resource getResource() {
        return resource;
    }
}

public interface Resource {
    Property<URI> getUri();
}

Here is another example using javax.inject.Inject:

build.gradle.kts
abstract class MyObjectFactoryTask
@Inject constructor(private var objectFactory: ObjectFactory) : DefaultTask() {

    @TaskAction
    fun doTaskAction() {
        val outputDirectory = objectFactory.directoryProperty()
        outputDirectory.convention(project.layout.projectDirectory)
        println(outputDirectory.get())
    }
}

tasks.register("myInjectedObjectFactoryTask", MyObjectFactoryTask::class) {}
build.gradle
abstract class MyObjectFactoryTask extends DefaultTask {
    private ObjectFactory objectFactory

    @Inject //@javax.inject.Inject
    MyObjectFactoryTask(ObjectFactory objectFactory) {
        this.objectFactory = objectFactory
    }

    @TaskAction
    void doTaskAction() {
        var outputDirectory = objectFactory.directoryProperty()
        outputDirectory.convention(project.layout.projectDirectory)
        println(outputDirectory.get())
    }
}

tasks.register("myInjectedObjectFactoryTask",MyObjectFactoryTask) {}

The MyObjectFactoryTask task uses an ObjectFactory instance, which is injected into the task’s constructor using the @Inject annotation.

ProjectLayout

ProjectLayout is a service that provides access to the layout of a Gradle project’s directories and files. It’s part of the org.gradle.api.file package and allows you to query the project’s layout to get information about source sets, build directories, and other file-related aspects of the project.

You can obtain a ProjectLayout instance from a Project object using the project.layout property. Here’s a simple example:

build.gradle.kts
tasks.register("showLayout") {
    doLast {
        val layout = project.layout
        println("Project Directory: ${layout.projectDirectory}")
        println("Build Directory: ${layout.buildDirectory.get()}")
    }
}
build.gradle
tasks.register('showLayout') {
    doLast {
        def layout = project.layout
        println "Project Directory: ${layout.projectDirectory}"
        println "Build Directory: ${layout.buildDirectory.get()}"
    }
}

Here is an example using javax.inject.Inject:

build.gradle.kts
abstract class MyProjectLayoutTask
@Inject constructor(private var projectLayout: ProjectLayout) : DefaultTask() {

    @TaskAction
    fun doTaskAction() {
        val outputDirectory = projectLayout.projectDirectory
        println(outputDirectory)
    }
}

tasks.register("myInjectedProjectLayoutTask", MyProjectLayoutTask::class) {}
build.gradle
abstract class MyProjectLayoutTask extends DefaultTask {
    private ProjectLayout projectLayout

    @Inject //@javax.inject.Inject
    MyProjectLayoutTask(ProjectLayout projectLayout) {
        this.projectLayout = projectLayout
    }

    @TaskAction
    void doTaskAction() {
        var outputDirectory = projectLayout.projectDirectory
        println(outputDirectory)
    }
}

tasks.register("myInjectedProjectLayoutTask",MyProjectLayoutTask) {}

The MyProjectLayoutTask task uses a ProjectLayout instance, which is injected into the task’s constructor using the @Inject annotation.

BuildLayout

BuildLayout is a service that provides access to the root and settings directory in a Settings plugin or a Settings script, it is analogous to ProjectLayout. It’s part of the org.gradle.api.file package to access standard build-wide file system locations as lazily computed value.

These APIs are currently incubating but eventually should replace existing accessors in Settings, which return eagerly computed locations:
Settings.rootDirSettings.layout.rootDirectory
Settings.settingsDirSettings.layout.settingsDirectory

You can obtain a BuildLayout instance from a Settings object using the settings.layout property. Here’s a simple example:

settings.gradle.kts
println("Root Directory: ${settings.layout.rootDirectory}")
println("Settings Directory: ${settings.layout.settingsDirectory}")
settings.gradle
println "Root Directory: ${settings.layout.rootDirectory}"
println "Settings Directory: ${settings.layout.settingsDirectory}"

Here is an example using javax.inject.Inject:

settings.gradle.kts
abstract class MyBuildLayoutPlugin @Inject constructor(private val buildLayout: BuildLayout) : Plugin<Settings> {
    override fun apply(settings: Settings) {
        println(buildLayout.rootDirectory)
    }
}

apply<MyBuildLayoutPlugin>()
settings.gradle
abstract class MyBuildLayoutPlugin implements Plugin<Settings> {
    private BuildLayout buildLayout

    @Inject //@javax.inject.Inject
    MyBuildLayoutPlugin(BuildLayout buildLayout) {
        this.buildLayout = buildLayout
    }

    @Override void apply(Settings settings) {
        // the meat and potatoes of the plugin
        println buildLayout.rootDirectory
    }
}

apply plugin: MyBuildLayoutPlugin

This code defines a MyBuildLayoutPlugin plugin that implements the Plugin interface for the Settings type. The plugin expects a BuildLayout instance to be injected into its constructor using the @Inject annotation.

ProviderFactory

ProviderFactory is a service that provides methods for creating different types of providers. Providers are used to model values that may be computed lazily in your build scripts.

The ProviderFactory interface provides methods for creating various types of providers, including:

  • provider(Callable<T> value) to create a provider with a value that is lazily computed based on a Callable.

  • provider(Provider<T> value) to create a provider that simply wraps an existing provider.

  • property(Class<T> type) to create a property provider for a specific type.

  • gradleProperty(Class<T> type) to create a property provider that reads its value from a Gradle project property.

Here’s a simple example demonstrating the use of ProviderFactory using project.providers:

build.gradle.kts
tasks.register("printMessage") {
    doLast {
        val providerFactory = project.providers
        val messageProvider = providerFactory.provider { "Hello, Gradle!" }
        println(messageProvider.get())
    }
}
build.gradle
tasks.register('printMessage') {
    doLast {
        def providerFactory = project.providers
        def messageProvider = providerFactory.provider { "Hello, Gradle!" }
        println messageProvider.get()
    }
}

The task named printMessage uses the ProviderFactory to create a provider that supplies the message string.

Here is an example using javax.inject.Inject:

build.gradle.kts
abstract class MyProviderFactoryTask
@Inject constructor(private var providerFactory: ProviderFactory) : DefaultTask() {

    @TaskAction
    fun doTaskAction() {
        val outputDirectory = providerFactory.provider { "build/my-file.txt" }
        println(outputDirectory.get())
    }
}

tasks.register("myInjectedProviderFactoryTask", MyProviderFactoryTask::class) {}
build.gradle
abstract class MyProviderFactoryTask extends DefaultTask {
    private ProviderFactory providerFactory

    @Inject //@javax.inject.Inject
    MyProviderFactoryTask(ProviderFactory providerFactory) {
        this.providerFactory = providerFactory
    }

    @TaskAction
    void doTaskAction() {
        var outputDirectory = providerFactory.provider { "build/my-file.txt" }
        println(outputDirectory.get())
    }
}

tasks.register("myInjectedProviderFactoryTask",MyProviderFactoryTask) {}

The ProviderFactory service is injected into the MyProviderFactoryTask task’s constructor using the @Inject annotation.

WorkerExecutor

WorkerExecutor is a service that allows you to perform parallel execution of tasks using worker processes. This is particularly useful for tasks that perform CPU-intensive or long-running operations, as it allows them to be executed in parallel, improving build performance.

Using WorkerExecutor, you can submit units of work (called actions) to be executed in separate worker processes. This helps isolate the work from the main Gradle process, providing better reliability and performance.

Here’s a basic example of how you might use WorkerExecutor in a build script:

build.gradle.kts
abstract class MyWorkAction : WorkAction<WorkParameters.None> {
    private val greeting: String = "Hello from a Worker!"

    override fun execute() {
        println(greeting)
    }
}

abstract class MyWorkerTask
@Inject constructor(private var workerExecutor: WorkerExecutor) : DefaultTask() {
    @get:Input
    abstract val booleanFlag: Property<Boolean>
    @TaskAction
    fun doThings() {
        workerExecutor.noIsolation().submit(MyWorkAction::class.java) {}
    }
}

tasks.register("myWorkTask", MyWorkerTask::class) {}
build.gradle
abstract class MyWorkAction implements WorkAction<WorkParameters.None> {
    private final String greeting;

    @Inject
    public MyWorkAction() {
        this.greeting = "Hello from a Worker!";
    }

    @Override
    public void execute() {
        System.out.println(greeting);
    }
}

abstract class MyWorkerTask extends DefaultTask {
    @Input
    abstract Property<Boolean> getBooleanFlag()

    @Inject
    abstract WorkerExecutor getWorkerExecutor()

    @TaskAction
    void doThings() {
        workerExecutor.noIsolation().submit(MyWorkAction) {}
    }
}

tasks.register("myWorkTask", MyWorkerTask) {}

See the worker API for more details.

FileSystemOperations

FileSystemOperations is a service that provides methods for performing file system operations such as copying, deleting, and syncing. It is part of the org.gradle.api.file package and is typically used in custom tasks or plugins to interact with the file system.

Here is an example using javax.inject.Inject:

build.gradle.kts
abstract class MyFileSystemOperationsTask
@Inject constructor(private var fileSystemOperations: FileSystemOperations) : DefaultTask() {

    @TaskAction
    fun doTaskAction() {
        fileSystemOperations.sync {
            from("src")
            into("dest")
        }
    }
}

tasks.register("myInjectedFileSystemOperationsTask", MyFileSystemOperationsTask::class)
build.gradle
abstract class MyFileSystemOperationsTask extends DefaultTask {
    private FileSystemOperations fileSystemOperations

    @Inject //@javax.inject.Inject
    MyFileSystemOperationsTask(FileSystemOperations fileSystemOperations) {
        this.fileSystemOperations = fileSystemOperations
    }

    @TaskAction
    void doTaskAction() {
        fileSystemOperations.sync {
            from 'src'
            into 'dest'
        }
    }
}

tasks.register("myInjectedFileSystemOperationsTask", MyFileSystemOperationsTask)

The FileSystemOperations service is injected into the MyFileSystemOperationsTask task’s constructor using the @Inject annotation.

With some ceremony, it is possible to use FileSystemOperations in an ad-hoc task defined in a build script:

build.gradle.kts
interface InjectedFsOps {
    @get:Inject val fs: FileSystemOperations
}

tasks.register("myAdHocFileSystemOperationsTask") {
    val injected = project.objects.newInstance<InjectedFsOps>()
    doLast {
        injected.fs.copy {
            from("src")
            into("dest")
        }
    }
}
build.gradle
interface InjectedFsOps {
    @Inject //@javax.inject.Inject
    FileSystemOperations getFs()
}

tasks.register('myAdHocFileSystemOperationsTask') {
    def injected = project.objects.newInstance(InjectedFsOps)
    doLast {
        injected.fs.copy {
            from 'source'
            into 'destination'
        }
    }
}

First, you need to declare an interface with a property of type FileSystemOperations, here named InjectedFsOps, to serve as an injection point. Then call the method ObjectFactory.newInstance to generate an implementation of the interface that holds an injected service.

This is a good time to consider extracting the ad-hoc task into a proper class.

ArchiveOperations

ArchiveOperations is a service that provides methods for accessing the contents of archives, such as ZIP and TAR files. It is part of the org.gradle.api.file package and is typically used in custom tasks or plugins to unpack archive files.

Here is an example using javax.inject.Inject:

build.gradle.kts
abstract class MyArchiveOperationsTask
@Inject constructor(
    private val archiveOperations: ArchiveOperations,
    private val layout: ProjectLayout,
    private val fs: FileSystemOperations
) : DefaultTask() {
    @TaskAction
    fun doTaskAction() {
        fs.sync {
            from(archiveOperations.zipTree(layout.projectDirectory.file("sources.jar")))
            into(layout.buildDirectory.dir("unpacked-sources"))
        }
    }
}

tasks.register("myInjectedArchiveOperationsTask", MyArchiveOperationsTask::class)
build.gradle
abstract class MyArchiveOperationsTask extends DefaultTask {
    private ArchiveOperations archiveOperations
    private ProjectLayout layout
    private FileSystemOperations fs

    @Inject
    MyArchiveOperationsTask(ArchiveOperations archiveOperations, ProjectLayout layout, FileSystemOperations fs) {
        this.archiveOperations = archiveOperations
        this.layout = layout
        this.fs = fs
    }

    @TaskAction
    void doTaskAction() {
        fs.sync {
            from(archiveOperations.zipTree(layout.projectDirectory.file("sources.jar")))
            into(layout.buildDirectory.dir("unpacked-sources"))
        }
    }
}

tasks.register("myInjectedArchiveOperationsTask", MyArchiveOperationsTask)

The ArchiveOperations service is injected into the MyArchiveOperationsTask task’s constructor using the @Inject annotation.

With some ceremony, it is possible to use ArchiveOperations in an ad-hoc task defined in a build script:

build.gradle.kts
interface InjectedArcOps {
    @get:Inject val arcOps: ArchiveOperations
}

tasks.register("myAdHocArchiveOperationsTask") {
    val injected = project.objects.newInstance<InjectedArcOps>()
    val archiveFile = "${project.projectDir}/sources.jar"
    doLast {
        injected.arcOps.zipTree(archiveFile)
    }
}
build.gradle
interface InjectedArcOps {
    @Inject //@javax.inject.Inject
    ArchiveOperations getArcOps()
}

tasks.register('myAdHocArchiveOperationsTask') {
    def injected = project.objects.newInstance(InjectedArcOps)
    def archiveFile = "${projectDir}/sources.jar"

    doLast {
        injected.arcOps.zipTree(archiveFile)
    }
}

First, you need to declare an interface with a property of type ArchiveOperations, here named InjectedArcOps, to serve as an injection point. Then call the method ObjectFactory.newInstance to generate an implementation of the interface that holds an injected service.

This is a good time to consider extracting the ad-hoc task into a proper class.

ExecOperations

ExecOperations is a service that provides methods for executing external processes (commands) from within a build script. It is part of the org.gradle.process package and is typically used in custom tasks or plugins to run command-line tools or scripts as part of the build process.

Here is an example using javax.inject.Inject:

build.gradle.kts
abstract class MyExecOperationsTask
@Inject constructor(private var execOperations: ExecOperations) : DefaultTask() {

    @TaskAction
    fun doTaskAction() {
        execOperations.exec {
            commandLine("ls", "-la")
        }
    }
}

tasks.register("myInjectedExecOperationsTask", MyExecOperationsTask::class)
build.gradle
abstract class MyExecOperationsTask extends DefaultTask {
    private ExecOperations execOperations

    @Inject //@javax.inject.Inject
    MyExecOperationsTask(ExecOperations execOperations) {
        this.execOperations = execOperations
    }

    @TaskAction
    void doTaskAction() {
        execOperations.exec {
            commandLine 'ls', '-la'
        }
    }
}

tasks.register("myInjectedExecOperationsTask", MyExecOperationsTask)

The ExecOperations is injected into the MyExecOperationsTask task’s constructor using the @Inject annotation.

With some ceremony, it is possible to use ExecOperations in an ad-hoc task defined in a build script:

build.gradle.kts
interface InjectedExecOps {
    @get:Inject val execOps: ExecOperations
}

tasks.register("myAdHocExecOperationsTask") {
    val injected = project.objects.newInstance<InjectedExecOps>()

    doLast {
        injected.execOps.exec {
            commandLine("ls", "-la")
        }
    }
}
build.gradle
interface InjectedExecOps {
    @Inject //@javax.inject.Inject
    ExecOperations getExecOps()
}

tasks.register('myAdHocExecOperationsTask') {
    def injected = project.objects.newInstance(InjectedExecOps)

    doLast {
        injected.execOps.exec {
            commandLine 'ls', '-la'
        }
    }
}

First, you need to declare an interface with a property of type ExecOperations, here named InjectedExecOps, to serve as an injection point. Then call the method ObjectFactory.newInstance to generate an implementation of the interface that holds an injected service.

This is a good time to consider extracting the ad-hoc task into a proper class.

ToolingModelBuilderRegistry

ToolingModelBuilderRegistry is a service that allows you to register custom tooling model builders. Tooling models are used to provide rich IDE integration for Gradle projects, allowing IDEs to understand and work with the project’s structure, dependencies, and other aspects.

The ToolingModelBuilderRegistry interface is part of the org.gradle.tooling.provider.model package and is typically used in custom Gradle plugins that provide enhanced IDE support.

Here’s a simplified example:

build.gradle.kts
// Implements the ToolingModelBuilder interface.
// This interface is used in Gradle to define custom tooling models that can
// be accessed by IDEs or other tools through the Gradle tooling API.
class OrtModelBuilder : ToolingModelBuilder {
    private val repositories: MutableMap<String, String> = mutableMapOf()

    private val platformCategories: Set<String> = setOf("platform", "enforced-platform")

    private val visitedDependencies: MutableSet<ModuleComponentIdentifier> = mutableSetOf()
    private val visitedProjects: MutableSet<ModuleVersionIdentifier> = mutableSetOf()

    private val logger = Logging.getLogger(OrtModelBuilder::class.java)
    private val errors: MutableList<String> = mutableListOf()
    private val warnings: MutableList<String> = mutableListOf()

    override fun canBuild(modelName: String): Boolean {
        return false
    }

    override fun buildAll(modelName: String, project: Project): Any {
        return "model"
    }
}

// Plugin is responsible for registering a custom tooling model builder
// (OrtModelBuilder) with the ToolingModelBuilderRegistry, which allows
// IDEs and other tools to access the custom tooling model.
class OrtModelPlugin(private val registry: ToolingModelBuilderRegistry) : Plugin<Project> {
    override fun apply(project: Project) {
        registry.register(OrtModelBuilder())
    }
}
build.gradle
// Implements the ToolingModelBuilder interface.
// This interface is used in Gradle to define custom tooling models that can
// be accessed by IDEs or other tools through the Gradle tooling API.
class OrtModelBuilder implements ToolingModelBuilder {
    private Map<String, String> repositories = [:]

    private Set<String> platformCategories = ["platform", "enforced-platform"]

    private Set<ModuleComponentIdentifier> visitedDependencies = []
    private Set<ModuleVersionIdentifier> visitedProjects = []

    private static final logger = Logging.getLogger(OrtModelBuilder.class)
    private List<String> errors = []
    private List<String> warnings = []

    @Override
    boolean canBuild(String modelName) {
        return false
    }

    @Override
    Object buildAll(String modelName, Project project) {
        return null
    }
}

// Plugin is responsible for registering a custom tooling model builder
// (OrtModelBuilder) with the ToolingModelBuilderRegistry, which allows
// IDEs and other tools to access the custom tooling model.
class OrtModelPlugin implements Plugin<Project> {
    ToolingModelBuilderRegistry registry

    OrtModelPlugin(ToolingModelBuilderRegistry registry) {
        this.registry = registry
    }

    void apply(Project project) {
        registry.register(new OrtModelBuilder())
    }
}

You can learn more at Tooling API.

TestEventReporterFactory Incubating

TestEventReporterFactory is a service that provides access to the test event reporting API.

You can learn more at Test Reporting API.

DependencyFactory

DependencyFactory is a service that provides methods for creating dependencies in a type-safe way.

You can learn more in the Implementing Binary Plugins guide.

DependencyConstraintFactory Incubating

DependencyConstraintFactory is a service that provides methods for creating DependencyConstraint instances in a type-safe way. It is the constraint-creation counterpart to DependencyFactory and is typically used by plugins that publish or consume dependency constraints.

The service is only available via @Inject, there is no project-level accessor.

build.gradle.kts
abstract class CreateConstraintTask
@Inject constructor(private var factory: DependencyConstraintFactory) : DefaultTask() {

    @TaskAction
    fun create() {
        val constraint = factory.create("com.example:lib:1.2.3")
        println("Created constraint: ${constraint.group}:${constraint.name}:${constraint.version}")
    }
}

tasks.register("createConstraint", CreateConstraintTask::class) {}
build.gradle
abstract class CreateConstraintTask extends DefaultTask {
    private DependencyConstraintFactory factory

    @Inject //@javax.inject.Inject
    CreateConstraintTask(DependencyConstraintFactory factory) {
        this.factory = factory
    }

    @TaskAction
    void create() {
        def constraint = factory.create("com.example:lib:1.2.3")
        println("Created constraint: ${constraint.group}:${constraint.name}:${constraint.version}")
    }
}

tasks.register("createConstraint", CreateConstraintTask) {}

The CreateConstraintTask task receives a DependencyConstraintFactory instance through its constructor using the @Inject annotation.

Problems Incubating

Problems is a service that allows tasks and plugins to report structured problems. Reported problems surface in the console, the HTML problems report, and through the Tooling API, so IDEs and Build Scan can render them consistently.

Obtain a ProblemReporter from the injected Problems service via problems.getReporter() and call report() (recoverable) or throwing() (fatal).

plugin/src/main/kotlin/org/example/HelloProblemsPlugin.kt
@get:Inject
abstract val problems: Problems
plugin/src/main/groovy/org/example/HelloProblemsPlugin.groovy
@Inject
abstract Problems getProblems()

You can learn more in the Reporting Plugin Problems with the Problems API guide.

BuildFeatures

BuildFeatures is a service that exposes the requested and active state of major Gradle features currently the Configuration Cache and Isolated Projects, so plugins can adapt their behavior accordingly.

A plugin can, for example, gate optional logic that is incompatible with Isolated Projects on the active state of that feature:

MyPlugin.java
public abstract class MyPlugin implements Plugin<Project> {

    @Inject
    protected abstract BuildFeatures getBuildFeatures(); (1)

    @Override
    public void apply(Project p) {
        BuildFeatures buildFeatures = getBuildFeatures();

        Boolean configCacheRequested = buildFeatures.getConfigurationCache().getRequested() (2)
            .getOrNull(); // could be null if user did not opt in nor opt out
        String configCacheUsage = describeFeatureUsage(configCacheRequested);
        MyReport myReport = new MyReport();
        myReport.setConfigurationCacheUsage(configCacheUsage);

        boolean isolatedProjectsActive = buildFeatures.getIsolatedProjects().getActive() (3)
            .get(); // the active state is always defined
        if (!isolatedProjectsActive) {
            myOptionalPluginLogicIncompatibleWithIsolatedProjects();
        }
    }

    private String describeFeatureUsage(Boolean requested) {
        return requested == null ? "no preference" : requested ? "opt-in" : "opt-out";
    }

    private void myOptionalPluginLogicIncompatibleWithIsolatedProjects() {
    }
}
1 The BuildFeatures service can be injected into plugins, tasks, and other managed types.
2 Use getRequested() to read the user’s opt-in or opt-out, returning a Provider<Boolean> that may be empty when the user expressed no preference.
3 Use getActive() to read whether the feature is actually active in the current build, returning a non-empty Provider<Boolean>.

You can learn more in the Implementing Binary Plugins guide.

FlowScope and FlowProviders Incubating

FlowScope and FlowProviders are services that together let a plugin register dataflow actions (isolated pieces of work that run when their input providers become available, such as at the end of a build).

FlowScope registers the actions; FlowProviders exposes build lifecycle events (such as the build work result) as Provider values that can be wired into action parameters. Both services are typically injected together into a project or settings plugin:

SoundFeedbackPlugin.java
package org.gradle.sample.sound;

import org.gradle.api.Plugin;
import org.gradle.api.flow.FlowProviders;
import org.gradle.api.flow.FlowScope;
import org.gradle.api.initialization.Settings;

import javax.inject.Inject;
import java.io.File;

public abstract class SoundFeedbackPlugin implements Plugin<Settings> {
    @Inject
    protected abstract FlowScope getFlowScope(); (1)

    @Inject
    protected abstract FlowProviders getFlowProviders(); (1)

    @Override
    public void apply(Settings settings) {
        final File soundsDir = new File(settings.getSettingsDir(), "sounds");
        getFlowScope().always( (2)
            SoundPlay.class,  (3)
            spec ->  (4)
                spec.getParameters().getMediaFile().set(
                    getFlowProviders().getBuildWorkResult().map(result -> (5)
                        new File(
                            soundsDir,
                            result.getFailure().isPresent() ? "sad-trombone.mp3" : "tada.mp3"
                        )
                    )
                )
        );
    }
}
1 Use service injection to obtain FlowScope and FlowProviders instances.
2 Register an action in the always scope so it runs at the end of every build.
3 Wire FlowProviders.getBuildWorkResult() into the action’s parameters so the action receives the success-or-failure outcome.

You can learn more in the Dataflow Actions reference.

BuildInvocationDetails Incubating

BuildInvocationDetails is a service that exposes information about the current build invocation, most notably the wall-clock time at which the build was started. It is useful for plugins that report build duration, emit timing metrics, or display a banner with the build’s start time.

The service is only available via @Inject, there is no project-level accessor.

build.gradle.kts
abstract class ReportBuildStartTask
@Inject constructor(private var invocationDetails: BuildInvocationDetails) : DefaultTask() {

    @TaskAction
    fun report() {
        val started = Date(invocationDetails.buildStartedTime)
        println("Build started at $started")
    }
}

tasks.register("reportBuildStart", ReportBuildStartTask::class) {}
build.gradle
abstract class ReportBuildStartTask extends DefaultTask {
    private BuildInvocationDetails invocationDetails

    @Inject //@javax.inject.Inject
    ReportBuildStartTask(BuildInvocationDetails invocationDetails) {
        this.invocationDetails = invocationDetails
    }

    @TaskAction
    void report() {
        def started = new Date(invocationDetails.buildStartedTime)
        println("Build started at $started")
    }
}

tasks.register("reportBuildStart", ReportBuildStartTask) {}

The ReportBuildStartTask task receives a BuildInvocationDetails instance through its constructor using the @Inject annotation.

SoftwareComponentFactory

SoftwareComponentFactory is a service that lets a plugin create AdhocComponentWithVariants instances (adhoc software components built from outgoing variants) for publication via the publishing plugins. It is typically used by plugins that produce custom component types and want to publish them without defining a full component model.

The service is only available via @Inject, there is no project-level accessor.

build.gradle.kts
// A plugin that uses SoftwareComponentFactory to create an adhoc software
// component, suitable for publishing custom variants. The factory is only
// available via @Inject — there is no project-level accessor.
class CustomComponentPlugin
@Inject constructor(private val componentFactory: SoftwareComponentFactory) : Plugin<Project> {

    override fun apply(project: Project) {
        val component = componentFactory.adhoc("custom")
        project.components.add(component)
    }
}
build.gradle
// A plugin that uses SoftwareComponentFactory to create an adhoc software
// component, suitable for publishing custom variants. The factory is only
// available via @Inject — there is no project-level accessor.
class CustomComponentPlugin implements Plugin<Project> {
    private SoftwareComponentFactory componentFactory

    @Inject //@javax.inject.Inject
    CustomComponentPlugin(SoftwareComponentFactory componentFactory) {
        this.componentFactory = componentFactory
    }

    void apply(Project project) {
        def component = componentFactory.adhoc("custom")
        project.components.add(component)
    }
}

The CustomComponentPlugin plugin receives a SoftwareComponentFactory instance through its constructor using the @Inject annotation, creates an adhoc component, and adds it to the project’s components container so it can be referenced by a publication.

Service injection patterns

There are two ways that services can be provided to an object.

Constructor injection

A service can be injected into the constructor of the class. The constructor must be public and annotated with the javax.inject.Inject annotation.

Gradle uses the declared type of each constructor parameter to determine the services that the object requires. The order of the constructor parameters and their names are not significant and can be whatever you like.

Here is an example that shows a task type that receives an WorkerExecutor via its constructor:

Download.java
public class Download extends DefaultTask {
    private final WorkerExecutor workerExecutor;

    // Inject an WorkerExecutor into the constructor
    @Inject
    public Download(WorkerExecutor workerExecutor) {
        this.workerExecutor = workerExecutor;
    }

    @TaskAction
    void run() {
        // ...use workerExecutor to run some work
    }
}

Property injection

A service can be injected by adding a property getter method annotated with the javax.inject.Inject annotation to the class.

Gradle defers the creation of the service until the getter method is called. This can be more performant than constructor injection.

The property getter method must be public or protected. Gradle uses the declared return type of the getter method to determine the service to make available.

The method should be abstract or, in cases where this isn’t possible, should have a dummy method body. The method body is discarded. The name of the property is not significant and can be whatever you like.

Here is an example that shows a task type that receives two services via property getter methods:

Download.java
public abstract class Download extends DefaultTask {
    // Preferrably, use an abstract getter method
    @Inject
    protected abstract ObjectFactory getObjectFactory();

    // Alternatively, use a getter method with a dummy implementation
    @Inject
    protected WorkerExecutor getWorkerExecutor() {
        // Method body is ignored
        throw new UnsupportedOperationException();
    }

    @TaskAction
    void run() {
        WorkerExecutor workerExecutor = getWorkerExecutor();
        ObjectFactory objectFactory = getObjectFactory();
        // Use the executor and factory ...
    }
}