Closed starksm64 closed 3 years ago
I haven't seen that conversation, but relying on compiling the same source twice sounds rather brittle to me. I find the Moditect approach easier to understand and more robust. But I'm not married to it, if there's a "mandate" to use this approach, that sounds fine to me too.
The conversation has been on the platform-dev list. We will discuss this in the platform call tomorrow.
The conclusion on the call is that if a spec API jar has no actual requirements on the Java 11 SE APIs, the module-info.class should be provided in the root of the jar as per the mechanism in this PR. A multi-release jar should only be used if a spec API jar has some mechanism via a helper class, etc. to call the Java 11 SE APIs.
OK so I'm not terribly fond of this double compilation approach. The Moditect Maven plugin makes it super-simple to put the module-info.class
into the root of the JAR, just delete the <jvmVersion>9</jvmVersion>
line. In any case, if we have to do this, then we just do it.
Also CC @rbygrave @overheadhunter @Emily-Jiang
While I'm fine with the approach of two compilations (using the same myself), I need to stress again, that the pre-modular Java world (including Android) may not like to find a Java 9 class inside the root of the jar.
I personally don't use Java 8 and neither do I use build tools or frameworks with fancy class loaders that load every .class they find in a jar. So I don't care. But some library vendors do care, as they don't want to risk breaking things.
Yes, specs allow to put the module-info into the root. And yes, we could argue that aforementioned tools that don't comply with specs are just stupid. But this would be a bad rationale to put compatibility at risk. So far I'm missing arguments against MR-Jars.
put compatibility at risk.
Yes. In the prior PR discussion we settled on MR Jar due to the compatibility risk.
So far I'm missing arguments against MR-Jars.
Yes. It would be good to know these arguments so that it's more obvious to us why they outweigh the compatibility risk that is mitigated by using MR Jar.
I think the pushback for MR jars is that it overly complicate things. Overall concensus is that module-info under root is much simplier. Besides, some specs might put module-info under version/9 and others put version/11 etc, which causes issues to scan for these locations.
For more info regarding this, please refer to the minutes for the Jakarta platform call yesterday.
@starksm64 I am with @Ladicek . I don't think you need to make so many changes. IIUC, just move the module-info under root and job done. You can still use the existing plugin and still use MR jar, which is allowed.
I am not sure whether we have to produce a MR jar. From yesterday's call:
module-info must be placed in the root of the JAR The four specs from JDK 8 already support module-info: Activation, XML Binding, XML web services, SOAP attachments, jsonp, mail, persistence, jsonb In case a spec wants/needs to support previous versions of Java, a multi-release JAR may be required for that spec (e.g., JAXB in EE 9/9.1) Multi-release JAR is not needed just for adding the module-info
I think the pushback for MR jars is that it overly complicate things. Overall concensus is that module-info under root is much simplier.
When you say "overly complicate", you're implying that there is a simpler solution with the same result. Sure, a module-info in the root is "simpler", but as mentioned multiple times, the results are not the same.
Besides, some specs might put module-info under version/9 and others put version/11 etc, which causes issues to scan for these locations.
Actually, it is an official standard for any module-aware JRE (and any other JRE or tool does not interact with module-info anyway). Therefore it is safe to assume that any tool that knows MR-Jars also knows module-info and vice versa.
What issues would that be? You don't need to decide to put versions into 9 and/or 11. At compile time, you simply store version-specific classes using the oldest supported version (potentially root). At runtime you load classes from all supported versions, ignore anything newer and resolve conflicts by using the newest supported version. You don't even need to worry about this, it is the JREs job to make these decisions.
just move the module-info under root and job done. You can still use the existing plugin and still use MR jar
That is a contradiction. Either you store it in the root or use the multi-version approach.
Let me explain my motivation in pushing this towards maximum compatibility: As said before, some library vendors (looking especially at Google here) don't want breaking changes. And as I use Google's Dagger library, I have an interest in Dagger switching from javax.inject
to jakarta.inject
. However, they won't do so, if jakarta.inject breaks downstream builds for users, who're stuck with Java 8. Specs are cool, but the reality is that some tools don't give a f** about specs and just load everything that ends with `.classinside a jar (maybe even from within
META-INFbut at least this exists a little longer than
module-info.class`, so apparently it got excluded).
The arguments against MR jars were:
Frankly the JPMS tech continues to be an experiment when it comes to user facing applications. We can simply produce two api artifacts and let users run their own experiments. The main jar would be the module-info.class in the root to be consistent with what the rest of the Jakarta specs are doing. A second MR jar with a mr qualifier can be produced in addition.
OK so I'm not terribly fond of this double compilation approach. The Moditect Maven plugin makes it super-simple to put the
module-info.class
into the root of the JAR, just delete the<jvmVersion>9</jvmVersion>
line. In any case, if we have to do this, then we just do it.
But it is introducing another plugin to set the module-info.class info rather than using the approach of adding the module-info.java to the source tree as is being done by every other spec project. My least favorite activity when looking at a spec project build is trying to figure out what non-basic plugins are doing.
We can simply produce two api artifacts and let users run their own experiments.
I like this, to me this sounds like the best approach and sounds similar to what was mooted in a previous PR (The Java 11 PR we closed).
To be more explicit, what I think was mooted was to release 2 artifacts:
With 2 artifacts we then support both cases nicely and people can choose.
So the plan would be to:
I like the idea of two different artifacts, but let me reframe it:
module-info.class
at the jar's root, jakarta namespace, consumers will most likely be on JDK 9+ anywayjavax.inject
- JDK 8 doesn't even know about mr jars, therefore it can not contain bugs when handling mr jars (mentioned by @starksm64), therefore (please hear me out) this artifact should be a MR-Jar:This approach should combine the most benefits:
2.0.1
1.0.4
(see #23)
1.0.3
if you have any problemsFrankly, I'm tired of rehashing the same arguments over and over again. (And I'm tired of having to point out an intrinsic inconsistency in the argument that "some tools scan all .class files, therefore we can't have module-info.class in the root, but we can put it info META-INF/versions, because surely those tools will ignore that location".)
Here's a proposal: we produce 2 JARs, but not 2.0.1 and 3.0. We produce 2.0.1
with module-info.class
in the root. We also produce 2.0.1-nomod
that will not include module-info.class
at all.
How does that sound?
EDIT: I see the previous comment contains a similar proposal. I believe we should just do what I described, because the MR JAR does not address the fear of breaking changes. Tools that scan for .class
files and pick up /module-info.class
cannot be expected to ignore /META-INF/versions/9/module-info.class
, simply because the reality is that some tools don't give a f*** about specs and just load everything.
Frankly, I'm tired of rehashing the same arguments over and over again. [...]
Me too. I'm not personally interested in these discussions, I just want to benefit from a modular jar.
But if downstream maintainers of some of the most wide-spread Java libs out there are unwilling to adapt such change, I will never know the true promise of this module-info. Therefore I feel the need to bring attention to those fears expressed by said library maintainers.
If this is not allowed, we can of course just close our eyes and live in a bubble where everything adheres specs. And you can believe me, I would love to live in this bubble as well.
Here's a proposal: we produce 2 JARs, but not 2.0.1 and 3.0. We produce
2.0.1
withmodule-info.class
in the root. We also produce2.0.1-nomod
that will not includemodule-info.class
at all.How does that sound?
Maybe I wasn't clear enough: There is no need for any such compromise. For the jakarta namespace it is safe to assume downstream projects are on a (mostly) modern tech stack. In other words: Just put the god damn module info into the jar's root and that's it. No need for a separate release.
The whole point of this PR is to reduce alleged complexity. This goal is hardly achieved by committing to maintaining two separate flavours of the same lib.
I would just say this: just produce a jar with module-info.class under root. Full stop! If someone has problems, they can either remove the module-info.class from the jar themselves or raise an issue here and we then produce another jar. I don't like the idea to producing a swiss knife just in case. Since it is so easy and simple to do a service release, just do one and wait for feedback. If we got some request, then add another one. There is no other specs releasing multiple api jars as far as I know. If we want to release two jars, another conversation on the platform needs to happen again. It takes time. I am not sure it worth it before we have a concrete use case - at the moment, it is based on some possible misuage.
So a 3.0.0 or even a 2.1.0 release is off the table for EE10 because both of those require a release plan with a specification committee vote. The initial deadline for specifications is Oct 15, so all we can do is a point service release.
This is what we'll do:
…-info.class
This is the approach that has been discussed on the platform dev list
Signed-off-by: Scott M Stark starksm64@gmail.com