[MSHADE-265] - Add module-info merging support - #829
Conversation
6cbc929 to
38ac043
Compare
90dc6e4 to
4cb31a5
Compare
ea84628 to
82abdc8
Compare
82abdc8 to
b3653b4
Compare
|
Rebased. |
b3653b4 to
a6a69e6
Compare
|
Rebased. |
a6a69e6 to
4569d75
Compare
| jos.putNextEntry(jarEntry); | ||
| outputManifest.write(jos); | ||
| } finally { | ||
| forceMultiRelease = false; |
There was a problem hiding this comment.
This worries me a bit. It suggests there's a specific order to call methods, and thread safety might be in play. Maybe forceMultiRelease and forceAutomaticModuleName should be arguments instead of fields. Not sure, but worth digging into
There was a problem hiding this comment.
I have made a change to limit the fields change only around the call to modifyOutputStream.
Threading should not be a problem. The transformers should be per-mojo invocation and within the invocation it is all a single thread. Unless the plugin itself spawns some threads.
elharo
left a comment
There was a problem hiding this comment.
The more I look at this the more unsure I am. The PR might be 100% correct and exactly what we need to do, but I don't know. What does shading a modular application even mean? Can we make shading work with JPMS, or is this something we fundamentally should not do?
Others might understand the issues involved here better than me.
| manifest = jarFile.getManifest(); | ||
| } | ||
| } | ||
| if (manifest != null |
There was a problem hiding this comment.
this might be able to be extracted to a private method and then pushed into the try blocks
There was a problem hiding this comment.
This does not look like an improvement to me.
| /** | ||
| * Controls how module descriptors are handled while shading. | ||
| */ | ||
| public enum ModuleInfoMode { |
There was a problem hiding this comment.
do enums have to be public?
| */ | ||
| public enum ModuleInfoMode { | ||
| /** Discard module descriptors, retaining the historical behavior. */ | ||
| discard, |
There was a problem hiding this comment.
These are usually UPPER CASE
| # Merging Java Module Descriptors | ||
|
|
||
| By default, the plugin discards every root and versioned `module-info.class` from the inputs. This preserves the | ||
| historical behavior: an unmodified descriptor would describe the original artifact rather than the contents of the |
There was a problem hiding this comment.
would describe --> describes
| ``` | ||
|
|
||
| Merge mode models the shaded JAR as if the retained, relocated source files had been compiled together as one module. | ||
| The primary artifact remains authoritative for the module name, version, main class, and, by default, the public |
There was a problem hiding this comment.
Is this right? Shouldn't a shaded jar change the module name? One purpose of shading is to allow multiple versions to exists in the classpath at the same time.
There was a problem hiding this comment.
Well, if you enable the modules merging in your plugin configuration then you are agreeing to have a module. It needs a name. Changing it does not make much sense to me. Users of your project either want to use the original JAR or the shaded JAR, not both at the same time. So having the same module name as the original JAR does not look like a problem.
There was a problem hiding this comment.
I don't like moving a direct negative, but no. Using both the original jar and the shaded jar at the same time is exactly why projects shade. They need to have both in the classpath, typically because some code need a fork or a different version and some code needs the original. Or maybe they need a very specific version and want to make sure the wrong version doesn't get added to the classpath. I suppose they use two different versions in this case but they still have the same module name unless this is changed.
There was a problem hiding this comment.
My usual use case is something like Netty being shaded into some sort of connector library JAR under a different package so that the connector does not depend on Netty version in dependencies. Renaming the packages in the normal JAR and distributing that, if I understand you correctly, sound unusual to me. But I accept that I don't know all the people's use cases.
I will add a way to change the module name, if possible.
elharo
left a comment
There was a problem hiding this comment.
JPMS is complex so perhaps there's something I'm misunderstanding here, but for now I think this is something we should not do. I'm not saying this PR is bad or can be fixed to be accepted. I'm saying this is a feature we should not have, and further work is unlikely to be accepted absent a clear and compelling explanation of why this should be done.
We can discuss the exact function of the merging. But it should be merge eventually because people asked for it. The mental model for how this works is in the OP. It works as if you pooled all the partial sources into one module, made some necessary adjustments, and compiled it as a single module. |
|
I have made the change to allow changing the resulting module name. |
|
"But it should be merge eventually because people asked for it." Um, no. People ask for features that are bad ideas all the time. It looks to me like this is one of those times. |
Add opt-in merging for root and multi-release module descriptors while preserving the primary module boundary. Cover relocation, services, modular-floor handling, filtering failures, Maven 3/4 compatibility, and reactor output directories during manifest processing. Keep the PR-owned tests aligned with the JUnit 5 migration on master. Fixes apache#629. Fixes apache#581. Fixes apache#588.
4a39b98 to
0792783
Compare
Summary
Add opt-in merging of Java module descriptors with:
The default remains
discard, preserving the plugin's existing behavior.The merge follows a source-amalgamation model: the primary artifact supplies the
module identity, while the shaded contents are treated as if their sources had
been relocated and compiled into that module. By default, the primary module's
exports and opens remain its public boundary. Users can opt into the effective
boundary of embedded modules or add explicit exports, opens, requirements, and
service uses where source-level intent cannot be inferred safely.
The processor:
requirements that collide with inactive descriptor or filename-derived names;
and materializing retained packages from embedded open modules when boundary
merging is requested;
automatic modules;
actionable guidance when dynamic service use cannot be inferred;
descriptor view used for merging;
ct.symandjmodsfrom a selected JDK,with optional toolchain requirements for release-aware analysis; and
Multi-release inputs are merged as cumulative release views. The implementation
rebuilds
ModulePackages, validates the invariants required of versioned moduledescriptors, and raises the modular floor when a provider or public-boundary
change cannot be represented at an earlier release. Earlier releases then retain
an automatic-module bridge with a stable
Automatic-Module-Name.Manifest processing now also accepts reactor output directories. Maven can expose
a reactor dependency as
target/classeswhen separate lifecycle tasks such aspackage testare requested. The manifest pre-scan reads a directory manifestwhen present, instead of attempting to open the directory as a JAR.
Documentation covers the defaults, public-boundary modes, explicit overrides,
toolchain selection, dynamic service use, and modular-floor behavior.
Fixes #629.
Fixes #581.
Fixes #588.
JIRA: MSHADE-265,
MSHADE-215
Validation
mvn test: 104 tests run, zero failures; one skipped.mvn test: 104 tests run, zero failures; 14 modular-runtime tests skipped.mvn -Prun-its verify: 86 integration projects passed, one skipped by itsJRE-version condition.
module-info-mergeproject passed when the built plugin was runwith Maven 3.6.3, current Maven 3.x, and Maven 4.
MSHADE-215project fails with Shade 3.6.2 and passes with thebranch build under Maven 3.6.3, current Maven 3.x, and Maven 4.
21 JVM and Maven 3.9.16; the branch build completed successfully in the same
environment.
mvn sitepassed.jar --validate,jar --describe-module,and
jdeps --check.Following this checklist to help us incorporate your
contribution quickly and easily:
for the change (usually before you start working on it). Trivial changes like typos do not
require a JIRA issue. Your pull request should address just this issue, without
pulling in other changes.
[MSHADE-XXX] - Fixes bug in ApproximateQuantiles,where you replace
MSHADE-XXXwith the appropriate JIRA issue. Best practiceis to use the JIRA issue title in the pull request title and in the first line of the
commit message.
mvn clean verifyto make sure basic checks pass. A more thorough check willbe performed on your pull request automatically.
mvn -Prun-its clean verify).If your pull request is about ~20 lines of code you don't need to sign an
Individual Contributor License Agreement if you are unsure
please ask on the developers list.
To make clear that you license your contribution under
the Apache License Version 2.0, January 2004
you have to acknowledge this by using the following check-box.
I hereby declare this contribution to be licenced under the Apache License Version 2.0, January 2004
In any other case, please file an Apache Individual Contributor License Agreement.