skip to content

Sources and Javadoc Jars

withSourcesJar and withJavadocJar to register those tasks and attach them as secondary variants of the java component. Asked because Maven Central requires both and a single line supplies them.

on this pageshow

questions

5

How do you make a Gradle Java library publish a sources jar and a javadoc jar alongside the main artifact?

level: juniorimportance: must knowfreq 70%

answer

  1. java { withSourcesJar(); withJavadocJar() }
  2. registers sourcesJar / javadocJar Jar tasks
  3. attached as secondary variants on java component
  4. from(components["java"]) picks them up
  5. classifiers sources / javadoc

basics

~10 s

Inside the java { } block call withSourcesJar() and withJavadocJar(). Gradle registers sourcesJar and javadocJar tasks and attaches them to the java component, so they publish automatically.

solid answer

~30 s

The `java` plugin extension exposes two opt-in methods: `withSourcesJar()` and `withJavadocJar()`. Calling them in the `java { }` block does three things: registers a `sourcesJar` task (a `Jar` packaging `main` sources, classifier `sources`), registers a `javadocJar` task (packaging the output of the `javadoc` task, classifier `javadoc`), and attaches each as a *secondary variant* on the `java` SoftwareComponent. Because they are part of the component, a `maven-publish` `from(components["java"])` publication picks them up with no extra wiring, and they are also described in Gradle Module Metadata. You no longer hand-create `Jar` tasks or call `artifacts { archives ... }` for the common case.

code

kotlin · 12 lines
kotlin
java {
    withSourcesJar()
    withJavadocJar()
}

publishing {
    publications {
        create<MavenPublication>("maven") {
            from(components["java"])
        }
    }
}

go deeper

for a junior

Know the two method names and that they go inside the java { } block to publish sources and javadoc.

for a middle

Explain that they register named Jar tasks and attach them to the java component so publishing picks them up automatically.

for a senior

Discuss secondary variants and module metadata, and contrast with the legacy hand-rolled Jar + archives approach.

for a principal

Frame as a publishing-policy default across many library modules (convention plugin) and the consumer-resolution implications via attributes.

## The problem Maven Central (and most repos) require a library to publish three things: the main `.jar`, a `-sources.jar`, and a `-javadoc.jar`. Historically you wrote these `Jar` tasks by hand and registered them with the `archives` configuration. Modern Gradle gives you two one-liners. ## The two methods The `java-library`/`java` plugin adds a `JavaPluginExtension` reachable via the `java { }` block. Two methods on it are relevant: - `withSourcesJar()` — registers a task named `sourcesJar` of type `Jar`. It bundles the `main` source set's sources (`.java`, resources) and uses the archive classifier `sources`. - `withJavadocJar()` — registers a task named `javadocJar` of type `Jar`. It depends on and packages the output of the built-in `javadoc` task, with classifier `javadoc`. Both are *opt-in* and idempotent: calling them more than once is safe, and not calling them means the tasks don't exist. ## Secondary variants The important part is what happens after registration. Each jar is attached to the `java` component as a **secondary variant** — a variant carrying attributes like `DocsType=sources` or `DocsType=javadoc` and category `documentation`. Because the variant lives on the component: - `from(components["java"])` in a `maven-publish` publication publishes all three jars and emits correct Gradle Module Metadata describing the variants. - A consumer can selectively resolve, say, the sources variant via attribute-based dependency resolution. ## Why prefer it over hand-rolled Jar tasks Manually creating `Jar` tasks still works, but you'd then have to attach them to the component (or the publication) yourself and they wouldn't automatically appear as proper documentation variants in module metadata. The `withXxxJar()` methods wire all of that correctly. ```kotlin plugins { `java-library`; `maven-publish` } java { withSourcesJar() withJavadocJar() } publishing { publications { create<MavenPublication>("lib") { from(components["java"]) // includes main + sources + javadoc } } } ```

  • What classifiers do the generated jars use?
    `sources` for the sources jar and `javadoc` for the javadoc jar — matching Maven conventions for `-sources.jar` and `-javadoc.jar`.
  • Do you need to add these jars to the publication manually?
    No. Because they are attached to the `java` component, `from(components["java"])` includes them automatically along with correct module metadata.

saying these in an interview costs you the question

  • Saying you must hand-create `Jar` tasks and use `artifacts { archives }` for sources/javadoc — that's the legacy approach the methods replace.
  • Claiming these are enabled by default — they are opt-in.

context

open as a page

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%

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.

open as a page

When you call `withJavadocJar()`, what does the resulting jar contain and which task does it depend on?

level: middleimportance: should knowfreq 40%

basics

~10 s

It packages the output of the built-in javadoc task (generated HTML docs) into a jar with classifier javadoc. The javadocJar task depends on javadoc, so running it triggers doc generation first.

open as a page

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%

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.

open as a page

A teammate added `tasks.register<Jar>("sourcesJar")` and `publication.artifact(sourcesJar)` instead of `withSourcesJar()`, and now consumers can't resolve sources via attributes. Why, and how do you fix it properly?

level: seniorimportance: should knowfreq 25%

basics

~20 s

artifact(sourcesJar) only attaches a file to the Maven publication; it doesn't create a documentation variant on the java component, so Gradle Module Metadata has no sources variant to match. Use withSourcesJar() (or attach the variant via AdhocComponentWithVariants).

open as a page