When publishing a library, why must each additional jar (sources, javadoc, etc.) set a distinct archiveClassifier, and what goes wrong if two jars share the same classifier?
answer
- one GAV, classifier disambiguates
- sources / javadoc / tests classifiers
- duplicate classifier+extension = collision
- withSourcesJar() / withJavadocJar()
- task archiveClassifier must match publication
basics
~20 sAll jars in one publication share the same group:name:version, so the classifier is the only thing that distinguishes them. Two jars with the same classifier collide — the publication fails or one overwrites the other.
solid answer
~50 sA Maven/Ivy publication groups several artifacts under one set of coordinates (`group:name:version`). The **classifier** (and extension) is what differentiates files within that GAV — `mylib-1.0.jar`, `mylib-1.0-sources.jar`, `mylib-1.0-javadoc.jar`. Each secondary `Jar` task you register must therefore set a unique `archiveClassifier` (`sources`, `javadoc`, `tests`, etc.); the main jar keeps an empty classifier. If two artifacts end up with the same classifier+extension, the publication has a collision: `maven-publish` will fail validation (duplicate artifact) or, depending on how artifacts are added, one silently overwrites the other and consumers can't request the intended file. Set the classifier with `archiveClassifier.set("sources")` inside the task. Note that the classifier on the **artifact** in the publication and the `archiveClassifier` on the producing task must stay consistent — usually you just register the jar with the right classifier and add it to the component or publication, letting Gradle derive the classifier from the task.
code
kotlin · 10 linesjava {
withSourcesJar() // registers sourcesJar with archiveClassifier 'sources'
withJavadocJar() // registers javadocJar with archiveClassifier 'javadoc'
}
// equivalent manual form:
tasks.register<Jar>("sourcesJar") {
archiveClassifier.set("sources")
from(sourceSets.main.get().allSource)
}go deeper
State that secondary jars need unique classifiers and name sources/javadoc.
Explain the one-GAV model, that classifier+extension disambiguates, and show withSourcesJar()/withJavadocJar() plus the manual equivalent.
Describe collision behavior (validation failure vs overwrite) and the need to keep task archiveClassifier consistent with the published artifact classifier.
Define a standard set of secondary artifacts and classifier conventions in a publishing convention plugin so all library modules expose sources/javadoc uniformly.
## One coordinate, many files When you publish, all artifacts in a single `MavenPublication` live under the same `group:name:version` (GAV). A repository stores them side by side. What tells them apart is the **classifier** plus the **extension**: ``` mylib-1.0.jar (main, classifier = "") mylib-1.0-sources.jar (classifier = sources) mylib-1.0-javadoc.jar (classifier = javadoc) mylib-1.0-tests.jar (classifier = tests) ``` ## Where the classifier comes from For a `Jar` task, the file name's classifier segment is `archiveClassifier`. The main artifact leaves it empty; each secondary jar sets a unique value: ```kotlin tasks.register<Jar>("sourcesJar") { archiveClassifier.set("sources") from(sourceSets.main.get().allSource) } tasks.register<Jar>("javadocJar") { archiveClassifier.set("javadoc") from(tasks.named("javadoc")) } ``` (The `java` plugin's `withSourcesJar()` / `withJavadocJar()` do exactly this for you.) ## What collisions break If two artifacts in the same publication share the same classifier+extension: - **Validation failure**: `maven-publish` detects a duplicate artifact and fails the build with a clear error. - **Silent overwrite**: if added in a way that bypasses validation, one file's bytes land at the same repository path and the other is lost — consumers requesting `:sources` may get the wrong content. - **Consumer confusion**: tools resolve artifacts by classifier; an ambiguous classifier means the IDE can't fetch sources or javadoc reliably. ## Consistency between task and publication The classifier embedded in the file name (`archiveClassifier`) should match the classifier the publication advertises. The clean approach is to register the jar with the correct `archiveClassifier` and let the component/publication infer the classifier from the artifact's task, rather than hardcoding a different classifier on the `artifact(...)` entry — mismatches lead to a file named one way but published under another classifier. ## Why this matters Sources and javadoc jars are core to a good developer experience: IDEs download them by classifier to show source and docs. Getting classifiers unique and consistent is what makes that work and keeps the publication valid.
- What shortcut does the java plugin give for sources and javadoc jars?`java { withSourcesJar(); withJavadocJar() }` registers the tasks with the correct classifiers and wires them into the main component/publication.
- What happens if you give two jars the classifier 'sources'?The publication has two artifacts with the same classifier+extension under one GAV, which is a collision — maven-publish fails validation or one overwrites the other.
saying these in an interview costs you the question
- Saying different jars need different versions to coexist (they share the version; classifier disambiguates).
- Believing two jars can share a classifier as long as their contents differ.
- Setting archiveClassifier on the task but a different classifier on the artifact() entry.