Where must input/output annotations be placed on a task class, and how does Gradle's property validation enforce correct declarations?
answer
- @get: use-site target in Kotlin
- metadata read from getters
- abstract val + Property/RegularFileProperty
- validatePlugins task
- untracked / conflicting / wrong-type problems
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.
solid answer
~40 sGradle reads input/output metadata from **getters**, so in Kotlin you must use the `@get:` use-site target — `@get:InputFile`, not a bare `@InputFile` (which would target the field/constructor param and be ignored). Properties are typically `abstract val` backed by Gradle's lazy types (`Property<T>`, `RegularFileProperty`, `ConfigurableFileCollection`), letting Gradle manage instantiation. At runtime (and via the `validatePlugins`/`ValidatePlugins` task) Gradle runs **property validation**: every public getter must be exactly one of an input annotation, an output annotation, or `@Internal`. Unannotated getters, conflicting combinations (e.g. both `@Input` and `@InputFile`), a missing-value non-optional input, or a `@Input` on a `File` produce validation problems — warnings today, and increasingly hard errors. This catches the silent stale-output bugs at build time rather than in production builds.
code
kotlin · 7 linesabstract class ManifestTask : DefaultTask() {
@get:Input abstract val appName: Property<String>
@get:InputFiles abstract val sources: ConfigurableFileCollection
@get:OutputFile abstract val manifest: RegularFileProperty
@get:Internal abstract val timestampFormatter: Property<DateTimeFormatter>
}
// `./gradlew validatePlugins` reports any getter that isn't input/output/@Internalgo deeper
Know annotations go on getters and in Kotlin you write @get:Input / @get:InputFile.
Explain the @get: trap and the use of abstract val with Property/RegularFileProperty.
Describe property validation rules and the validatePlugins task as the safety net for correct declarations.
Mandate validatePlugins (failing) in CI for all published plugins so input/output defects can't reach consumers.
## Annotations live on getters Gradle inspects the task type's **getter methods** for input/output metadata. In Java you annotate the getter directly. In Kotlin, a property's annotation defaults to the *property/field*, so you must use the `@get:` use-site target: ```kotlin @get:InputFile // correct — targets the getter abstract val template: RegularFileProperty // @InputFile val template ... // WRONG in Kotlin: not on the getter, ignored ``` This is one of the most common Kotlin DSL mistakes — the build compiles but the input is invisible. ## Abstract properties + lazy types Modern task types declare `abstract val` properties of lazy types: - `Property<T>` for values - `RegularFileProperty` / `DirectoryProperty` for files/dirs - `ConfigurableFileCollection` for sets Gradle generates the implementation (managed properties), so you never write backing fields. These integrate with `@get:Input`/`@get:InputFile` cleanly. ## Property validation Gradle validates task and plugin types. Rules include: - **Missing annotation**: a public getter that is none of input/output/`@Internal` → 'is not annotated' problem. - **Conflicting annotations**: e.g. both `@Input` and `@OutputFile` on one getter. - **Wrong type**: `@Input` on a `File`/`FileCollection` → 'has @Input annotation used on property of type File' problem (you wanted `@InputFile`). - **Missing value**: a non-`@Optional` input with no configured value. - **Private getter** carrying an annotation that Gradle can't see. You run this explicitly with the `validatePlugins` task (from the `java-gradle-plugin` plugin), and Gradle also performs lightweight checks during task execution. Validation problems are reported as warnings and, depending on Gradle version/strictness, can fail the build. ## Why it matters Property validation turns 'I forgot `@get:`' from a silent incremental-build corruption into a build-time diagnostic. For plugin authors it's the safety net that keeps published tasks correctly cacheable and incremental.
- In Kotlin, why does a bare @InputFile (without @get:) fail to register the input?Kotlin's default annotation use-site for a property is the field/property, not the getter. Gradle reads metadata from getters, so without @get: the annotation lands somewhere Gradle never inspects and the input is silently untracked.
- How do you run input/output validation as part of CI?Apply the java-gradle-plugin plugin and run the validatePlugins task (or include it in check). It scans task/plugin types and reports problems like untracked, conflicting, or wrongly-typed properties; you can configure it to fail the build.
saying these in an interview costs you the question
- Putting annotations on fields/constructor params in Kotlin instead of @get:.
- Assuming validation only documents problems — it can fail the build and prevents silent incrementality bugs.
- Declaring both a value and a file annotation on the same getter.