Skip to content

Latest commit

 

History

History
110 lines (82 loc) · 3.85 KB

File metadata and controls

110 lines (82 loc) · 3.85 KB
Previous: Anatomy of a Gradle Plugin Table of Contents Next: Lifecycle of a Gradle Build

Managed Types and Properties

Further Reading:

Gradle provides us with some tools to make building plugins easier. Particularly around creating types with less boilerplate. We'll cover how to use these and what it does behind the scenes.

Managed types

Gradle has a concept of a "managed type". This is an abstract class that contains "managed properties" and should be the preferred way to make types in Gradle.

An example managed type is the extension we saw in the previous section:

public abstract class HelloExtension {
    public abstract Property<String> getName();
    public abstract RegularFileProperty getOutputFile();
}

Here, we have an abstract class with no implementation that defines two properties, name and outputFile. When we instantiate it as an extension:

project.getExtension().create("hello", HelloExtension.class);

Gradle makes an implementation class with all the boilerplate like this:

public final class HelloExtension_Generated extends HelloExtension {
    private final Property<String> name;
    private final RegularFileProperty outputFile;
    
    @Inject
    public HelloExtension_Generated(ObjectFactory objects) {
        this.name = objects.property(String.class);
        this.outputFile = objects.fileProperty();
    }
    
    @Override
    public Property<String> getName() {
        return name;
    }
    
    @Override
    public RegularFileProperty getOutputFile() {
        return outputFile;
    }
}

This is very similar to the commonly used immutables library. However, it is aware of Gradle types so will automatically create instances of properties (and other Gradle services) for us.

It is possible to write extensions and tasks directly as in the HelloExtension_Generated class above. If you look into the depths of older Palantir Gradle code you will find many instances of this, but this is no longer recommended. All new code should use Managed Types.

Why prefer create over add for extensions?

Prefer register an extension via

project.getExtensions().create("name", MyExtension.class);

rather than

project.getExtensions().add("name", new MyExtension(/* … */));

create asks Gradle to

  • build a managed instance (using Gradle’s code-generation),
  • wire that instance into Gradle’s lifecycle and dependency-injection system

This is mostly stylistic but is important as our Errorprones are built to detect extensions instantiated via create

Tasks

Similarly, for tasks, they should look like below rather than being manually specified:

public abstract class SomeTask extends DefaultTask {
    @Input
    public abstract Property<String> getName();
    
    @Output
    public abstract RegularFileProperty getOutputFile();
    
    @TaskAction
    public final void action() {
        // ...
    }
} 

Note

This repository ships with the NonAbstractGradleType errorprone, which automatically fixes your Gradle tasks to be abstract.


Previous: Anatomy of a Gradle Plugin Table of Contents Next: Lifecycle of a Gradle Build