skip to content

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