What does the @Classpath input annotation do, and why would you use it instead of @InputFiles for a collection of jars?
answer
- order significant, name/path ignored
- content hash of jar entries
- @InputFiles uses absolute path by default
- relocatable + cacheable
- @CompileClasspath = ABI only
basics
~10 s@Classpath marks a task input as a classpath: Gradle hashes the file contents in order but ignores file names and paths. @InputFiles treats each file's absolute path as significant, so it over-invalidates.
solid answer
~40 s`@Classpath` tells Gradle that a property is a *classpath* — an ordered list of jars or class directories. For up-to-date checks and the build cache, Gradle hashes the **content** of each entry, respects their **order** (classpath order is semantically meaningful), but **ignores the names and paths** of the jar files. `@InputFiles` (or `@InputFiles @PathSensitive`) instead fingerprints individual files where name/path can matter, so a renamed or relocated jar — common with dependency caches on different machines — needlessly invalidates the task. Using `@Classpath` makes the task cacheable and relocatable across machines, which is exactly what you want for `compile`/`runtime` classpaths. There's also `@CompileClasspath` for the narrower case where only the API (public signatures) matters.
code
kotlin · 7 linesabstract class BundleTask : DefaultTask() {
@get:Classpath
abstract val runtimeJars: ConfigurableFileCollection
@get:OutputFile
abstract val bundle: RegularFileProperty
}go deeper
Know that @Classpath ignores file names/paths but keeps order, so tasks stay up-to-date when only the path changes.
Explain content-hashing of jar entries and why this makes tasks relocatable and cacheable across machines.
Contrast @Classpath vs @CompileClasspath, and explain how default path sensitivity on @InputFiles causes cache misses.
Frame it as a relocatability/cache-correctness concern across a fleet of CI agents and developer machines.
## What a classpath input is A *classpath* is an **ordered** sequence of jars and class directories handed to the JVM or to `javac`. Two properties make it special compared with an arbitrary file collection: 1. **Order matters** — the first class found on the classpath wins, so reordering can change behaviour. 2. **Names/paths do not matter** — `guava-32.jar` resolved into `~/.gradle/caches/...` on one machine and a different absolute path on a CI agent is the *same* dependency. The file name and directory are accidents of where the dependency cache lives. ## How Gradle fingerprints inputs Gradle computes a **fingerprint** of every task input to decide up-to-date status and to form the build-cache key. By default `@InputFiles` uses `ABSOLUTE` path sensitivity unless told otherwise, meaning the absolute path of each file is part of the hash. For a classpath that's wrong: it makes the task non-relocatable (cache misses between machines) and over-sensitive to harmless renames. ## @Classpath Annotating a property with `@Classpath`: - Hashes the **content** of each entry. - Preserves **order** of the entries. - **Ignores** the file names and the paths. - For jar files it hashes the *contents of the jar* (the entries inside), not the jar bytes, so a rebuilt jar with a different timestamp but identical classes produces the same fingerprint. This is the correct annotation for a *runtime* classpath input. ## @CompileClasspath `@CompileClasspath` is a stricter sibling for *compile* classpaths: it ignores everything that can't affect compilation — method bodies, private members, resources inside jars, debug info — and fingerprints only the **ABI** (public type signatures). Changing a method body of an upstream library therefore does **not** invalidate downstream compilation, only the recompiled jar's own consumers' runtime tasks. ## Code ```kotlin abstract class BundleTask : DefaultTask() { @get:Classpath abstract val runtimeJars: ConfigurableFileCollection @get:CompileClasspath abstract val apiJars: ConfigurableFileCollection @get:OutputFile abstract val bundle: RegularFileProperty @TaskAction fun bundle() { /* ... */ } } ``` Built-in tasks already do this: `JavaCompile.classpath` is `@CompileClasspath`, and runtime-oriented tasks use `@Classpath`. You only reach for these annotations on **custom** tasks.
- Why does @Classpath hash the contents of a jar rather than the jar file's bytes?Because jar files embed timestamps and ordering that change on every rebuild even when the compiled classes are identical. Hashing the logical entries inside makes the fingerprint stable across rebuilds.
- Does @Classpath ignore the order of the entries?No — order is preserved and significant, since classpath order determines which class wins when names collide. Only names and paths are ignored.
Think of a classpath like a stack of numbered transparencies: the order you stack them changes the picture, but it doesn't matter what's scribbled on the back (the file name) or which drawer they came from (the path).
saying these in an interview costs you the question
- Saying @Classpath ignores ordering — it does not; order is significant.
- Claiming @Classpath and @InputFiles are interchangeable for jars.
- Thinking @Classpath hashes the raw jar bytes (it hashes the entries inside).