Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
8 changes: 6 additions & 2 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,12 @@ All notable changes to this documentation project will be documented in this fil

* Initial repository structure
* README with project overview
* Documentation build pipeline (Maven + AsciiDoctor)
* Documentation build pipeline (Apache Maven + AsciiDoctor)
* GitHub Actions workflow for CI/CD
* Netlify deployment for PR previews
* GitHub Pages deployment for main branch
* `docs/index.adoc` with documentation outline
* `docs/index.adoc` with documentation outline

'''

_Apache Maven is a trademark of the https://www.apache.org/[Apache Software Foundation]._
8 changes: 6 additions & 2 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
////
= Maven Modular Sources Documentation
= Apache Maven Modular Sources Documentation
:icons: font
:toc: left
:toclevels: 2
Expand Down Expand Up @@ -70,4 +70,8 @@ Generated documentation will be in `target/generated-docs/`.

== License

Documentation is provided under the Apache License 2.0.
Documentation is provided under the Apache License 2.0.

'''

_Apache Maven is a trademark of the https://www.apache.org/[Apache Software Foundation]._
10 changes: 7 additions & 3 deletions docs/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
////
= Java Modules in Maven: Documentation
= Java Modules in Apache Maven: Documentation
:icons: font
:toc: left
:toclevels: 2
Expand Down 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 Expand Up @@ -134,4 +134,8 @@ To add new documentation:

. Create an AsciiDoc file in this directory
. Add an entry to the table in the Topics section
. Submit a pull request for review
. Submit a pull request for review

'''

_Apache Maven is a trademark of the https://www.apache.org/[Apache Software Foundation]._
241 changes: 241 additions & 0 deletions docs/vision.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
////
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 Apache 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.
Their source code can be organized in a single source tree, separated by module names.
This allows Maven to compile multiple Java Modules in one project into multiple modular JAR files efficiently.
Maven resolves external dependencies and assembles the module-path, enabling the compiler and JVM to enforce proper module boundaries.

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*.

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 setting up the module source path and module path for the compiler.
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 of dependency JARs 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 by design::
Maven 3 was built around the flat classpath model; no encapsulation enforcement at the JVM level.

When Java Modules arrived, Maven 3 adapted minimally:

* The compiler plugin (and others) gained module-path support
* Each Java Module still requires its own Maven module
* No native support for multi-module compilation
* Automatic detection of whether to place a dependency on classpath or module-path, with limited control when detection was wrong
* No easy way to set up `--patch-module` for whitebox testing; a common workaround was to overwrite `module-info.java` in the test directory, which has drawbacks

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.
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.

'''

_Apache Maven is a trademark of the https://www.apache.org/[Apache Software Foundation]._