gnodet commented on issue #11642:
URL: https://github.com/apache/maven/issues/11642#issuecomment-4224389770
## Analysis: Making Maven 4 truly modular (JPMS)
_Claude Code on behalf of Guillaume Nodet_
I performed a comprehensive analysis of the Maven 4 codebase to understand
what it would take to assign `Automatic-Module-Name` entries (and eventually
full `module-info.java` descriptors) to all published Maven artifacts. Here are
the findings.
---
### Current State
- **No `module-info.java`** files exist anywhere in the Maven 4 codebase
- **No `Automatic-Module-Name`** manifest entries are configured in any
module
- Maven 4 does have infrastructure to **detect and handle** JPMS in user
projects (`PathModularization`, `DependencyResolverResult`), but its own JARs
are not modularized
---
### Module Inventory
| Layer | Modules | Published JARs |
|-------|---------|----------------|
| API | 11 | 11 |
| Impl | 10 | 9 (maven-support has no source) |
| Compat | 14 | 14 |
| **Total** | **35** | **34** |
---
### Proposed Automatic Module Names
#### API Modules (clean — no package overlaps among themselves)
| ArtifactId | Proposed Module Name | Top-level Package |
|------------|---------------------|-------------------|
| maven-api-annotations | `org.apache.maven.api.annotations` |
`org.apache.maven.api.annotations` |
| maven-api-xml | `org.apache.maven.api.xml` | `org.apache.maven.api.xml` |
| maven-api-model | `org.apache.maven.api.model` |
`org.apache.maven.api.model` |
| maven-api-settings | `org.apache.maven.api.settings` |
`org.apache.maven.api.settings` |
| maven-api-toolchain | `org.apache.maven.api.toolchain` |
`org.apache.maven.api.toolchain` |
| maven-api-metadata | `org.apache.maven.api.metadata` |
`org.apache.maven.api.metadata` |
| maven-api-plugin | `org.apache.maven.api.plugin.descriptor` |
`org.apache.maven.api.plugin.descriptor` |
| maven-api-di | `org.apache.maven.api.di` | `org.apache.maven.api.di` |
| maven-api-core | `org.apache.maven.api` | `org.apache.maven.api` |
| maven-api-spi | `org.apache.maven.api.spi` | `org.apache.maven.api.spi` |
| maven-api-cli | `org.apache.maven.api.cli` | `org.apache.maven.api.cli` |
#### Impl Modules
| ArtifactId | Proposed Module Name | Top-level Package |
|------------|---------------------|-------------------|
| maven-di | `org.apache.maven.di` | `org.apache.maven.di` |
| maven-xml | `org.apache.maven.internal.xml` |
`org.apache.maven.internal.xml` |
| maven-jline | `org.apache.maven.jline` | `org.apache.maven.jline` |
| maven-logging | `org.apache.maven.logging` |
`org.apache.maven.logging.api` |
| maven-impl | `org.apache.maven.impl` | `org.apache.maven.impl` |
| maven-core | `org.apache.maven.core` | `org.apache.maven` (many
sub-packages) |
| maven-cli | `org.apache.maven.cling` | `org.apache.maven.cling` |
| maven-executor | `org.apache.maven.executor` |
`org.apache.maven.cling.executor` |
| maven-testing | `org.apache.maven.testing` |
`org.apache.maven.api.di.testing` |
#### Compat Modules (problematic — see below)
| ArtifactId | Proposed Module Name | Notes |
|------------|---------------------|-------|
| maven-artifact | `org.apache.maven.artifact` | Split packages with
maven-compat |
| maven-model | `org.apache.maven.model.compat` | Split with
maven-model-builder |
| maven-plugin-api | `org.apache.maven.plugin.api` | Split with maven-compat
|
| maven-settings | `org.apache.maven.settings.compat` | Split with
maven-compat |
| maven-builder-support | `org.apache.maven.building` | Clean |
| maven-repository-metadata | `org.apache.maven.repository.metadata.compat`
| Split with maven-compat |
| maven-model-builder | `org.apache.maven.model.builder` | Split with
maven-model |
| maven-settings-builder | `org.apache.maven.settings.builder` | Clean |
| maven-toolchain-model | `org.apache.maven.toolchain.model.compat` | Clean |
| maven-toolchain-builder | `org.apache.maven.toolchain.builder` | Clean |
| maven-resolver-provider | `org.apache.maven.repository.internal` | Clean |
| maven-compat | `org.apache.maven.compat` | Heavily split |
| maven-embedder | `org.apache.maven.embedder` | Clean |
---
### Critical Issue: Split Packages
JPMS forbids two named modules from exporting the same package. The analysis
found **21 split packages** across Maven modules. These fall into three
categories:
#### 1. API ↔ Impl splits (1 split)
| Package | Modules |
|---------|---------|
| `org.apache.maven.api.cli` | `maven-api-cli` + `maven-executor` |
**Fix:** Move `Executor`, `ExecutorException`, `ExecutorRequest` from
`maven-executor` to `maven-api-cli`, or relocate them to a distinct package
like `org.apache.maven.executor`.
#### 2. Impl ↔ Compat splits (13 splits)
`maven-core` shares 13 packages with various compat modules:
| Package | Compat Module(s) |
|---------|-------------------|
| `org.apache.maven` | maven-compat |
| `org.apache.maven.artifact` | maven-artifact, maven-compat |
| `org.apache.maven.artifact.handler` | maven-artifact |
| `org.apache.maven.artifact.repository` | maven-artifact, maven-compat |
| `org.apache.maven.artifact.repository.layout` | maven-artifact,
maven-compat |
| `org.apache.maven.artifact.resolver.filter` | maven-artifact, maven-compat
|
| `org.apache.maven.execution` | maven-compat |
| `org.apache.maven.model.plugin` | maven-model-builder |
| `org.apache.maven.plugin` | maven-compat, maven-plugin-api |
| `org.apache.maven.plugin.internal` | maven-compat |
| `org.apache.maven.project` | maven-compat |
| `org.apache.maven.project.artifact` | maven-compat |
| `org.apache.maven.settings` | maven-compat, maven-settings |
#### 3. Compat ↔ Compat splits (13 splits)
Multiple compat modules share packages among themselves (e.g.,
`maven-artifact` and `maven-compat` share 8 packages, `maven-model` and
`maven-model-builder` share `org.apache.maven.model.merge`).
#### 4. API namespace in impl layer
`impl/maven-impl` contains 23 classes in
`org.apache.maven.api.services.model` — a package using the API namespace
convention but living in the implementation layer. This would need to be
relocated or promoted to an API module.
---
### Recommended Approach
#### Phase 1: Add `Automatic-Module-Name` to API modules (low risk, high
value)
The 11 API modules have **zero package overlaps among themselves** and form
a clean module graph. Adding `Automatic-Module-Name` to these is safe and
immediately unblocks downstream projects like Quarkus:
```xml
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<Automatic-Module-Name>${module.name}</Automatic-Module-Name>
</manifestEntries>
</archive>
</configuration>
</plugin>
```
These are the modules that downstream projects actually depend on, so this
covers the primary use case from the issue.
#### Phase 2: Add `Automatic-Module-Name` to clean impl modules (low risk)
Modules like `maven-di`, `maven-xml`, `maven-jline`, `maven-logging`, and
`maven-impl` have no package overlaps and can safely receive automatic module
names.
#### Phase 3: Fix split packages in impl layer (medium effort)
- Move `org.apache.maven.api.cli.Executor*` classes out of the API namespace
in `maven-executor`
- Relocate `org.apache.maven.api.services.model` classes in `maven-impl` to
`org.apache.maven.impl.model.spi` or similar
- Address the `maven-core` splits with compat modules by relocating
compat-side classes to distinct packages where feasible
#### Phase 4: Compat layer (hard, possibly deferred)
The compat modules have extensive split packages **by design** — they
preserve the Maven 3 module/package structure where the same package was spread
across multiple JARs. Options:
1. **Do not modularize compat modules** — they remain on the classpath as
unnamed modules. This is pragmatic since they are deprecated.
2. **Merge split compat modules** into fewer JARs to eliminate splits
(breaking change for anyone depending on individual compat JARs).
3. **Relocate classes** to eliminate splits (breaking change for direct
class references).
Option 1 is recommended: compat modules should stay classpath-only, and
downstream projects should migrate to the Maven 4 API.
#### Phase 5: Full `module-info.java` (future)
Once automatic module names are stable, full module descriptors can be added
incrementally, starting with the leaf API modules (`maven-api-annotations`,
`maven-api-xml`) and working up the dependency graph.
---
### Summary
| Phase | Scope | Risk | Modules |
|-------|-------|------|---------|
| 1 | API `Automatic-Module-Name` | Low | 11 modules |
| 2 | Clean impl `Automatic-Module-Name` | Low | 5 modules |
| 3 | Fix impl split packages | Medium | 3 modules (executor, impl, core) |
| 4 | Compat layer decision | High | 14 modules (recommend: leave
classpath-only) |
| 5 | Full `module-info.java` | High | All modules incrementally |
Phase 1 alone addresses the original request and benefits downstream
consumers. Phases 2-3 are incremental improvements. Phase 4 is a design
decision. Phase 5 is a long-term goal.
--
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]