skip to content

What does `withSourcesJar()` do beyond just creating a Jar task — how does it integrate with the java component and publishing?

level: middleimportance: must knowfreq 55%

answer

  1. registers Jar task + sourcesElements configuration
  2. consumable, attributes Category=documentation DocsType=sources
  3. secondary variant on AdhocComponentWithVariants
  4. publishing + module metadata pick it up
  5. manual artifact() misses the variant

basics

~10 s

It registers the sourcesJar task and attaches the jar as a secondary variant on the java SoftwareComponent. So from(components["java"]) publishes it automatically and Gradle Module Metadata describes it as a documentation variant.

solid answer

~40 s

`withSourcesJar()` isn't just task creation — its value is *component integration*. It registers a `Jar` task (`sourcesJar`, classifier `sources`) and then adds it to the `java` component as a **secondary variant** carrying attributes like `Category=documentation`, `DocsType=sources`, `Bundling=external`. Two payoffs: (1) any `maven-publish`/`ivy-publish` publication built with `from(components["java"])` includes the jar and emits correct Gradle Module Metadata describing the variant, so attribute-aware consumers can resolve sources separately; (2) you don't touch the `archives` configuration or the `artifacts {}` block. Without the method you'd register the `Jar` task yourself AND attach it (e.g. via `AdhocComponentWithVariants.addVariantsFromConfiguration` or a publication `artifact(...)`), which is more error-prone and may omit metadata.

code

kotlin · 9 lines
kotlin
java {
    withSourcesJar() // -> sourcesJar task + sourcesElements consumable config
}

// equivalent secondary-variant attributes Gradle sets:
//   org.gradle.category   = documentation
//   org.gradle.docstype   = sources
//   org.gradle.usage      = (none / docs)
//   org.gradle.dependency.bundling = external

go deeper

for a junior

Know it both creates the task and makes publishing include the sources jar automatically.

for a middle

Explain the secondary-variant attachment and the consumable sourcesElements configuration with documentation attributes.

for a senior

Detail the attributes, AdhocComponentWithVariants, and how module metadata enables attribute-based consumption of sources.

for a principal

Reason about variant governance across a multi-module platform and consumer tooling (IDE sources resolution) implications.

## Component vs. task A *task* produces a file. A **SoftwareComponent** is Gradle's abstraction of "what gets published" — it groups variants (usages) such as `apiElements`, `runtimeElements`, plus optional documentation variants. The `java` component is the standard one for libraries. ## What `withSourcesJar()` actually does 1. Registers a `Jar` task named `sourcesJar` packaging the `main` source set, classifier `sources`. 2. Creates (or reuses) a *consumable* configuration for the sources, e.g. `sourcesElements`, marked `canBeConsumed = true`, `canBeResolved = false`, with attributes: - `Category` = `documentation` - `DocsType` = `sources` - `Bundling` = `external` 3. Adds that configuration to the `java` component as a **secondary variant** (the component is an `AdhocComponentWithVariants` under the hood). `withJavadocJar()` does the same with `DocsType=javadoc` and a `javadocElements` configuration. ## Why secondary variant matters Because the variant lives on the component, two systems pick it up for free: - **Publishing**: `from(components["java"])` enumerates the component's variants, so all attached jars are published and written into Gradle Module Metadata (`module.json`). The metadata declares `available-at`/variant entries with the attributes above. - **Consumption**: a consumer can request `DocsType=sources` via attribute-based resolution (e.g. an IDE pulling sources) and Gradle matches the right variant. ## Contrast with manual wiring ```kotlin // manual equivalent — fragile val sourcesJar by tasks.registering(Jar::class) { archiveClassifier.set("sources") from(sourceSets.main.get().allSource) } // you'd still need to attach it as a variant or add it to the publication publishing.publications.withType<MavenPublication> { artifact(sourcesJar) // publishes the file but NOT as a proper documentation variant in module metadata } ``` The manual `artifact(sourcesJar)` route publishes the file but does not create the documentation variant in module metadata. `withSourcesJar()` does both, which is why it's the recommended path.

  • Is the sources configuration resolvable or consumable?
    Consumable (`canBeConsumed = true`, `canBeResolved = false`). It exposes the artifact to consumers/publishing; it is not used to resolve a dependency graph.
  • Why does `artifact(sourcesJar)` on a publication behave differently?
    It attaches the file to the Maven publication but does not register a documentation variant on the component, so Gradle Module Metadata won't describe it as a sources variant for attribute-aware consumers.

saying these in an interview costs you the question

  • Saying `withSourcesJar()` only creates a task — missing the component/variant integration is the key point.
  • Confusing consumable and resolvable: the sources configuration is consumable, not resolvable.

context