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]

Reply via email to