Authoring Task Types
Writing your own task class: the action method, annotated inputs and outputs, normalization, incremental execution, cacheability, and dependency wiring. Interviewers ask because a well-authored task type is what makes a build both fast and correct.
on this pageshowhide
explore
- DefaultTask Subclasses & @TaskAction5 questions
- Typed @Input / @Output Properties5 questions
- Path Sensitivity & Input Normalization5 questions
- Incremental Tasks with InputChanges5 questions
- @CacheableTask & Build Cache Keys5 questions
- Task Dependencies & Ordering Hooks5 questions
- CommandLineArgumentProvider5 questions
- Local State and Destroyable Outputs5 questions
questions
page 2 of 2What does InputChanges.isIncremental mean, and how should an incremental task behave when it is false?
basics
~20 sisIncremental is true only when Gradle can give a reliable per-file delta. When false (first run, missing outputs, a non-@Incremental input changed), getFileChanges reports every file as ADDED, so your action effectively performs a full rebuild.
What are the main correctness pitfalls when authoring an incremental task, and how do you avoid them?
basics
~20 sCommon pitfalls: forgetting @Incremental on the queried property, not handling REMOVED, assuming you're always on an incremental run, deriving outputs non-deterministically, and querying a property you didn't mark @Incremental. Avoid them with deterministic input→output mapping and a full-rebuild-safe ADDED branch.
Where must input/output annotations be placed on a task class, and how does Gradle's property validation enforce correct declarations?
basics
~20 sAnnotations go on the property getter (in Kotlin, use @get:Input etc.). Gradle's property validation checks every public getter is classified as an input, output, or @Internal, and warns (or fails) on untracked or conflicting properties.
How do @OutputFile and @OutputDirectory participate in up-to-date checks, and why does declaring outputs matter beyond just naming the result?
basics
~10 s@OutputFile/@OutputDirectory tell Gradle what a task produces. Gradle fingerprints outputs too, so it detects manual deletion or tampering and reruns. Declared outputs also let Gradle wire task dependencies and clean stale outputs.
When would you choose @PathSensitive(NAME_ONLY) or NONE over RELATIVE for a task input? Give a concrete correctness consideration.
basics
~20 sUse NONE when only file content matters and location is irrelevant (e.g. a config blob). Use NAME_ONLY when the filename is significant but its directory isn't. Both are looser than RELATIVE, giving more cache hits — but only if the tool truly ignores the dropped path info.
Beyond declaring inputs, what makes a task's outputs safe to cache, and how would you make a task that currently produces non-reproducible outputs cacheable?
basics
~20 sOutputs must be reproducible: the same inputs must always yield the same bytes, with no timestamps, absolute paths, or randomness baked in. Make archives reproducible (fixed timestamps, sorted entries) and remove machine-specific data before marking the task cacheable.
Your custom task uses @InputFiles for a jar classpath, and the build cache never hits across CI agents. Walk through diagnosing and fixing the input normalization.
basics
~20 sPlain @InputFiles defaults to ABSOLUTE path sensitivity and full byte content, so jar timestamps and agent paths bust the fingerprint. Switch the property to @Classpath (or @CompileClasspath for compile inputs) so paths are ignored and jars are normalized, making the fingerprint portable.
Can a custom task have multiple @TaskAction methods, and how do task actions and doFirst/doLast relate?
basics
~10 sYes, a task can have several @TaskAction methods; Gradle runs them in declaration order. doFirst and doLast add extra actions that run before and after the @TaskAction methods on the task's action list.
How do you supply dynamic, cacheable compiler arguments to a JavaCompile task using a CommandLineArgumentProvider, and how does it differ from options.compilerArgs?
basics
~10 sAdd a CommandLineArgumentProvider to JavaCompile's options.compilerArgumentProviders. Like raw options.compilerArgs the strings reach javac, but the provider lets you annotate underlying file/value inputs so up-to-date checks and the build cache stay correct.
What is @ReplacedBy used for, and why can't you just rename an input/output property and replace its annotation?
basics
~20 s@ReplacedBy marks a deprecated getter that has been superseded by a new property, telling Gradle the old getter is NOT an input/output to track. It avoids double-counting the same value during a backward-compatible API migration on a task type.
showing 31–40 of 40