-
Notifications
You must be signed in to change notification settings - Fork 1
Add Vision document for Java Modules in Maven 4 #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
07cac49
0ecef2f
934431b
569e61f
97bba6e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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. | ||
|
|
||
| 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*. | ||
|
ascheman marked this conversation as resolved.
Outdated
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. | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't "module path" be "paths to module source files"?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was mostly thinking of the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. | ||
|
|
||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
|
|
||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Other limitations were:
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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). | ||
|
|
||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. | ||
|
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. | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. | ||
Uh oh!
There was an error while loading. Please reload this page.