skip to content

How can you customize the generated `sourcesJar` task — for example, excluding files or adding extra inputs — given that you didn't create it yourself?

level: seniorimportance: should knowfreq 35%

answer

  1. tasks.named<Jar>("sourcesJar") { ... }
  2. it's a normal Jar task
  3. exclude / from / manifest
  4. don't re-register same name (collision)
  5. lazy provider, config-cache friendly

basics

~10 s

withSourcesJar() registers a real Jar task named sourcesJar, so you configure it like any task: tasks.named<Jar>("sourcesJar") { exclude(...); from(...) }. You don't recreate it; you reach for it by name.

solid answer

~40 s

Even though `withSourcesJar()` creates the task for you, it's an ordinary `Jar` task registered under the name `sourcesJar`, fully configurable via the lazy API. Use `tasks.named<Jar>("sourcesJar") { ... }` to add `exclude("**/secret/**")`, append generated sources with `from(...)`, or tweak `archiveClassifier`/manifest. Order matters with configuration: call `withSourcesJar()` first so the task exists, then configure it. Avoid creating a *second* `Jar` named `sourcesJar` — that collides. Because configuration is lazy (`named` returns a provider), your tweaks apply without forcing eager creation. The same applies to `javadocJar`. This is the clean alternative to abandoning the helper and hand-rolling the whole task plus its variant wiring.

code

kotlin · 7 lines
kotlin
java { withSourcesJar() }

tasks.named<Jar>("sourcesJar") {
    exclude("**/internal/**")
    from(layout.buildDirectory.dir("generated/sources"))
    duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}

go deeper

for a junior

Know the task is named sourcesJar and can be referenced.

for a middle

Configure it via tasks.named<Jar>("sourcesJar") { exclude/from } without recreating it.

for a senior

Explain lazy named vs eager getByName, name-collision pitfalls, and ordering relative to the helper.

for a principal

Define standard customizations (exclusions for secrets/generated code) once in a convention plugin applied org-wide.

## The task is yours to configure `withSourcesJar()` doesn't hide the task — it registers a standard `org.gradle.api.tasks.bundling.Jar` task named `sourcesJar`. Everything you'd do to a hand-made jar you can do here through Gradle's lazy configuration API: ```kotlin java { withSourcesJar() } tasks.named<Jar>("sourcesJar") { exclude("**/generated/**") // drop noise from(layout.buildDirectory.dir("extra-src")) // add inputs manifest { attributes("Built-By" to "ci") } } ``` ## Why `named`, not `getByName`/creating anew - `tasks.named(...)` returns a `TaskProvider` and defers configuration until the task is actually needed — this keeps configuration-time work lazy and configuration-cache friendly. - Creating your own `tasks.register<Jar>("sourcesJar")` after `withSourcesJar()` throws a duplicate-name error. If you truly want full control, *don't* call `withSourcesJar()` and instead register the task and attach it as a variant yourself — but you lose the automatic component wiring. ## Ordering Call `withSourcesJar()` before referencing `sourcesJar`, otherwise the named task doesn't exist yet. Within a single build script this is usually fine since `named` is lazy, but if you reference it in a different plugin/phase, ensure the extension method ran first. ## What you typically customize - `exclude(...)` / `include(...)` patterns to keep secrets or generated code out. - Extra `from(...)` inputs (e.g. generated sources from annotation processors or codegen). - `duplicatesStrategy` when merging multiple source roots. - `archiveClassifier` only if you have a strong reason — changing it can break Maven `-sources.jar` conventions. The key insight for interviews: enabling the helper and customizing the resulting named task are not mutually exclusive — you get convenience *and* control.

  • Why use `tasks.named` instead of `tasks.getByName`?
    `named` returns a lazy `TaskProvider` and defers configuration, which avoids eager task realization and works well with the configuration cache. `getByName` realizes the task immediately.
  • What breaks if you call `tasks.register<Jar>("sourcesJar")` after `withSourcesJar()`?
    A duplicate task name error — the helper already registered `sourcesJar`. Configure the existing one or skip the helper entirely and wire it yourself.

saying these in an interview costs you the question

  • Saying you must abandon `withSourcesJar()` to customize the jar — you can configure the named task.
  • Re-registering a task with the same name, causing a collision.

context