gnodet opened a new issue, #13396: URL: https://github.com/apache/maven/issues/13396
## Summary Projects using JPMS **module source hierarchy** (a single `pom.xml` producing multiple JPMS module JARs via `<sources><source><module>…`) currently fail at install time because Maven unconditionally creates a main artifact for `jar` packaging, even though no single main JAR is produced. The `Packaging` API lacks a way to express "this packaging does not produce a main artifact." ## Background Related: - [MNG-8137 — Goal jar unconditionally replace main artifact](https://github.com/apache/maven/issues/10482) - [maven-install-plugin PR #466 — workaround: skip main artifact when its file is a directory](https://github.com/apache/maven-install-plugin/pull/466) - [maven-jar-plugin commit `f09e78d` — warn and skip JAR creation for packaging without main artifact](https://github.com/apache/maven-jar-plugin/commit/f09e78d) ## The Bug Chain 1. **`DefaultProjectBuilder.finishProjectInitialization()`** unconditionally creates a main artifact for every project, regardless of packaging or source hierarchy. 2. **`DefaultProject.artifacts()`** includes the main artifact whenever it's coordinate-wise different from the POM artifact. For `jar` packaging (`extension:"jar"` vs `"pom"`), they always differ → `mainArtifact()` always returns non-empty. 3. **`maven-jar-plugin` in module hierarchy mode** creates N attached JARs (one per JPMS module with `artifactId = moduleName`) but **never writes to the main artifact slot** — the main artifact keeps pointing at `target/classes/` (a directory). 4. **`maven-install-plugin`** iterates `projectManager.getAllArtifacts(project)`, finds the main artifact fails `Files.isRegularFile()` → **BUILD FAILURE**: `"Is a directory"`. ## Analysis ### What works today (the `pom` packaging precedent) For `pom` packaging, the system already handles "no main artifact" correctly: - `MavenProject.getArtifact()` is non-null (the POM artifact — backward compat) - But `DefaultProject.artifacts()` returns a 1-element list because POM artifact and project artifact have the same coordinates (`ArtifactIdUtils.equalsVersionlessId()` returns `true`) - `Project.mainArtifact()` returns `Optional.empty()` - Install/deploy, reactor reader, etc. all cope ### What's missing The "no main artifact" behavior for `pom` is an **accidental side effect** of the POM artifact and project artifact sharing the same extension. There is no explicit API for a packaging type to declare "I don't produce a main artifact." This is the missing piece. ## Proposed Changes ### 1. Add `producesMainArtifact()` to `Packaging` API ```java // api/maven-api-core/.../Packaging.java default boolean producesMainArtifact() { return true; } ``` This makes the concept first-class rather than an accidental coordinate-comparison side effect. ### 2. Wire it into `DefaultProject.artifacts()` ```java // impl/maven-core/.../DefaultProject.java — artifacts() method if (packaging.producesMainArtifact() && !ArtifactIdUtils.equalsVersionlessId(pomArtifact, projectArtifact)) { result.add(session.getArtifact(ProducedArtifact.class, projectArtifact)); } ``` - `MavenProject.getArtifact()` stays **non-null** (backward compat — no NPEs in legacy code) - `Project.mainArtifact()` returns `Optional.empty()` when packaging says no main artifact - Install/deploy already handle this correctly (proven by `pom` packaging) ### 3. Support module source hierarchy Two options (not mutually exclusive): **Option A — New packaging type (`modules`):** - `ModulesLifecycleMappingProvider` with `@Named("modules")` — same lifecycle bindings as `jar` but `producesMainArtifact() = false` - Users write `<packaging>modules</packaging>` - Clean and explicit **Option B — Auto-detection from `<sources>` model:** - `DefaultPackagingRegistry` or `DefaultProject` detects module source hierarchy via `SourceQueries.usesModuleSourceHierarchy()` (which already exists) - Dynamically sets `producesMainArtifact() = false` - Users keep `<packaging>jar</packaging>` — it "just works" ### 4. Fix JAR plugin early-return guard The recent guard in `AbstractJarMojo.execute()` ([`f09e78d`](https://github.com/apache/maven-jar-plugin/commit/f09e78d)) returns early when `project.getMainArtifact().isEmpty()`. This would prevent module hierarchy JARs from being created if a new packaging makes `mainArtifact()` empty. Needs: ```java if (project.getMainArtifact().isEmpty() && !usesModuleSourceHierarchy()) { // warn and return } ``` ### 5. (Nice-to-have) Improve `ReactorReader` `ReactorReader.getProjectArtifacts()` hardcodes `"pom".equals(project.getPackaging())` to skip the main artifact. Should use the packaging flag instead. The `isRegularFile` filter at line 408 is already a safety net, so this is non-critical. ## Files That Need Changes | File | Change | |---|---| | `api/maven-api-core/.../Packaging.java` | Add `producesMainArtifact()` default method | | `impl/maven-core/.../DefaultProject.java` | Check `producesMainArtifact()` in `artifacts()` | | `impl/maven-core/.../DefaultPackagingRegistry.java` | Pass flag to `DefaultPackaging` record | | `impl/maven-core/.../packaging/` | New lifecycle mapping provider (if Option A) | | `impl/maven-core/.../ReactorReader.java` | Replace hardcoded `"pom"` check (nice-to-have) | | **maven-jar-plugin** `AbstractJarMojo.java` | Don't early-return when module source hierarchy detected | ## Why the Install Plugin Workaround is Insufficient [PR #466](https://github.com/apache/maven-install-plugin/pull/466) filters out the main artifact at install time, but: - The main artifact still "exists" in `Project.mainArtifact()` — confusing for all API consumers - Deploy plugin would need the same workaround - Every future plugin that inspects project artifacts would need to handle this case - It advises users to switch to `pom` packaging, which is misleading The fix belongs in Maven core's `Packaging` API, making the concept explicit and letting all downstream consumers (install, deploy, reactor, etc.) benefit. _Claude Code on behalf of Guillaume Nodet_ -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
