Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ This documentation covers the following topics:
[[table:topics:introduction]]
2+| *Introduction to Maven and Java Modules*

| Vision (TBD)
| xref:vision.adoc[Vision]
| Shift from Maven modules to Java Modules as primary compilation units

| Architecture (TBD)
Expand Down
234 changes: 234 additions & 0 deletions docs/vision.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
////
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
////
= Vision: Java Modules and Maven (4)
:icons: font
:toc: left
:toclevels: 2

ifdef::env-github[]
:tip-caption: :bulb:
:note-caption: :information_source:
:important-caption: :heavy_exclamation_mark:
:caution-caption: :fire:
:warning-caption: :warning:
endif::[]

[sidebar]
.TL;DR
****
Java Modules enable strong encapsulation and explicit dependencies at the language level.
It is possible to define them in a single source tree separated by module names.
Doing so allows Maven to compile multiple Java Modules in one project to a similar structure of Java Classes efficiently.
Comment thread
ascheman marked this conversation as resolved.
Outdated

Using this opportunity to provide modularization on the language level imposes a significant shift in how Maven works with modules.
In particular, the *1:1 relationship of Maven module to major artifact (JAR) is no longer valid*.
Comment thread
ascheman marked this conversation as resolved.
Outdated
Comment thread
ascheman marked this conversation as resolved.
Outdated

Each Maven project may result in multiple artifacts (JARs), each representing a Java Module in the future.
Consequently, many existing Maven concepts and mechanisms need to be revisited to align with this new reality.
****

== How Java Modules work

Java Modules (aka _Java Platform Module System_ or _Project Jigsaw_, introduced in Java 9) provide compile-time and runtime encapsulation through `module-info.java` descriptors.

Key characteristics:

Explicit dependencies::
`requires`-declarations explicitly state which modules a module depends on.
The module system ensures required modules are present and permits access between modules.

Strong encapsulation::
Only `exports`-declared packages are accessible to other modules.

Compile-time and runtime verification::
Both the compiler and the JVM enforce module boundaries.
The compiler catches access violations where possible, and the runtime system enforces encapsulation even for reflective access (thus improving security).

Multi-module compilation::
The Java compiler can compile an entire module graph from a structured source tree and handles full and incremental compilation efficiently across module boundaries.

== Lifecycle Phases and Module Enforcement

Understanding when Maven is in control versus when the JVM takes over is fundamental to understanding the challenges of Java Module support.

=== Three Distinct Phases

Compile time::
Maven orchestrates the build environment by resolving dependencies and constructing the module path.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't "module path" be "paths to module source files"?

@ascheman ascheman Feb 5, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was mostly thinking of the module-path, with modular dependencies as JARs, directories of such JARs or perhaps other (unpacked modular class file diretories). I'll think about a reformulation.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clarified the text to distinguish between module source path and module path. Maven now "sets up the module source path and module path for the compiler" and "translates its dependency model into the module path of dependency JARs." Fixed in commit 569e61f.

The Java compiler (`javac`) enforces module boundaries during compilation, checking `requires` declarations and `exports` visibility.
Maven translates its dependency model (coordinates, scopes) into the module path that `javac` expects.

Test time::
Maven continues to orchestrate, but testing introduces additional complexity.
Whitebox testing (accessing internal packages) requires `--patch-module` to merge test code into the module under test.
The compiler and JVM both participate in enforcement during this phase.
Maven must set up the test environment to satisfy both compilation requirements and runtime test execution.

Runtime::
*Maven is no longer involved.*
The JVM's module system takes full control, enforcing boundaries based solely on the `module-info.class` files embedded in JARs.
No `pom.xml` is consulted; no Maven coordinates exist at this level.
The application runs (or fails) based purely on Java Module semantics.

[CAUTION]
====
This simplified model covers the typical case where Maven builds and packages artifacts that later run independently.
Special cases exist where Maven controls runtime execution, (e.g., via the Maven Exec Plugin, mixed module-path and classpath execution, or integration tests).
We do not address these scenarios here.
====

=== The Responsibility Boundary

[cols="1,1,1,2",options="header"]
|===
| Phase | Orchestrator | Enforcer | What Drives Configuration

| Compile
| Maven
| `javac`
| `pom.xml` dependencies + Project's Java Modules → module path

| Test
| Maven
| `javac` + JVM
| `pom.xml` + test-specific flags (`--patch-module`)

| Runtime
| JVM only
| JVM
| `module-info.class` in packaged JARs
|===

The critical insight: *Maven's responsibility ends at packaging.*
Once Maven has produced and deployed JARs, they must be self-sufficient.
The `module-info.class` in each JAR must accurately declare what the JVM will need to run the application.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But we still need to specify a module-path. However, the module-path could point to a single directory containing all JAR files, and the JVM will pickup only what it needs according module-info.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Qualified "Classpath-based" to "Classpath-based by design" and added: "With Java Modules, the JVM requires a module-path to resolve modules at runtime, but Maven 3's architecture remained classpath-centric." Fixed in commit 569e61f.

=== Why This Distinction Matters

This phase separation is the root cause of several challenges in Maven's Java Module support:

* *Metadata must bridge two worlds*: Maven produces artifacts at build time, but those artifacts must satisfy JVM requirements at runtime — without Maven present.

* *Semantic translation is imperfect*: Java Module concepts (`requires static`, `requires transitive`) express runtime behavior, while Maven concepts (`optional`, scopes) express build-time relationships. These don't map 1:1.

* *Build tool independence*: Consumers may use Gradle, Bazel, or manual compilation.
The `module-info.class` is the universal contract — it must be correct regardless of how a particular build system created it.

The <<Implications>> section outlines specific areas where these challenges manifest and require documentation.

== How Maven worked with Modules in the past

Maven 3's module concept predates Java Modules and serves a different purpose:

Maven modules::
Organizational units in a reactor build, each with its own `pom.xml`.

One module = one artifact::
Each Maven module produces exactly one primary artifact (JAR, WAR, etc.).

Classpath-based::
The JVM resolves dependencies by a flat classpath; no encapsulation enforcement.

When Java Modules arrived, Maven 3 adapted minimally:

* The compiler plugin (and others) gained module support
* Each Java Module still requires its own Maven module
* No native support for multi-module compilation

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other limitations were:

  • Automatic detection of whether to place a dependency on class-path or module-path, with no control in case of wrong detection.
  • No easy way to setup options such as --patch-module for whitebox testing. Instead, a common practice was to overwrite the full module-info.java file in the test, which has drawbacks.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incorporated both points into the Maven 3 adaptation list: classpath/module-path auto-detection with limited control, and the module-info.java overwrite workaround for whitebox testing. Fixed in commit 569e61f.

This 1:1 mapping works but limits the benefits of the new multi-module compilation model.

== How Maven (4) envisions Modules

=== Module Source Hierarchy

Maven 4 embraces the *Module Source Hierarchy* pattern (-> _modular sources_), allowing a single Maven project to compile multiple Java Modules:

[source,text]
----
project/
├── pom.xml
└── src/
├── moda/
│ └── main/java/
│ ├── module-info.java
│ └── pkga/Main.java
└── modb/
└── main/java/
├── module-info.java
└── pkgb/B.java
----

The Maven compiler plugin maps this layout directly to respective calls to `javac`, enabling:

Single compilation::
The Java compiler handles all modules together with proper (Java Module) dependency checking.

Overlapping dependency concepts::
- Java Module dependencies drive compilation, including project-internal module resolution as well as runtime behavior.
- Maven coordinates enable artifact resolution (project-external modules) and publication (see below).

Flexible artifact mapping::
One Maven project can produce multiple module JARs (in the future).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request is almost ready, waiting only for 4.0.0-rc-6 release: apache/maven-jar-plugin#508

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't want to explicitly refer to PR #508 but intentionally avoided referencing ongoing work in the vision document. I plan to cover artifact naming details in a separate document.

The POM declares sources explicitly:

[source,xml]
----
<build>
<sources>
<source><module>moda</module></source>
<source><module>modb</module></source>
</sources>
</build>
----

Maven subprojects (formerly known and declared as "modules") become optional organizational boundaries, not mandatory per-Java-Module requirements.

=== Two Levels of Dependency Resolution

With modular sources, dependency resolution operates at two distinct levels:

Java Module resolution::
The compiler and JVM resolve dependencies among modules by name.
Within the project's modular sources, the compiler handles this automatically.
At runtime, the JVM verifies that all required modules are present and accessible.

Maven artifact resolution::
Maven must still resolve external dependencies (libraries outside the project's modular sources)using Group, Artifact, and Version coordinates.
Comment thread
ascheman marked this conversation as resolved.
Outdated
Maven locates these artifacts and makes them available to the compiler and (test) runtime as modules.
The `module-info.java` declares its requirements by module name; Maven's `pom.xml` maps those names to resolvable artifacts.

== Implications

The shift to modular sources requires documenting several areas in detail.
The following topics are covered (or planned) as separate documents:

Consumer POM Generation (TBD)::
How Maven 4 generates consumer POMs that accurately reflect Java Module dependencies for downstream consumers.

Dependency Scope Mapping (TBD)::
Analysis of how Java Module modifiers (`requires static`, `requires transitive`) map to Maven scopes — and where they don't.

Testing Patterns (TBD)::
How whitebox testing works with `--patch-module` and how Maven 4's compiler plugin handles test sources automatically.

Artifact Naming (TBD)::
How Java module names map to Maven artifact coordinates when one project produces multiple JARs.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In above-cited pull request for Maven JAR plugin, the Java module name maps directly to the artifact name.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. I am preparing additional documents (including artifact naming analysis) but wanted the vision document to pass review first before expanding the scope.


See the xref:index.adoc#section:topics[Topics] overview for the full list of documentation areas.