jakartaee / platform

The Jakarta EE Platform project produces the Jakarta EE platform specification, which is an umbrella specification that aggregates all other Jakarta EE specifications.
https://jakartaee.github.io/platform/
Eclipse Public License 2.0
197 stars 65 forks source link

We need to define the JPMS strategy for EE10 and beyond #329

Closed starksm64 closed 2 years ago

starksm64 commented 3 years ago

Is your feature request related to a problem? Please describe. We have a problem with inconsistent JPMS usage for the platform APIs jars.

Describe the solution you'd like We need to clearly define the requirements for supporting JPMS.

Describe alternatives you've considered The current approach of allowing specification projects to define the level of JPMS support has produced an inconsistent experience for users/servers attempting to use JPMS.

starksm64 commented 3 years ago

Previous issues:

174

starksm64 commented 3 years ago

Ideas on various levels of details that are needed based on internal discussions:

keilw commented 3 years ago

It may be a special niche but based on Bugs at least until Java 13 not fully addressed (so if the minimum JDK version was 11-13 there is a great risk of that) JPMS and Multi-Release-JAR mechanism are incompatible and may cause serious problems if used together without safety-measures.

Most of that is hidden very well in OpenJDK Bugs like JDK-8207162 and similar ones, but even the statement it affects only Java 9-11 seems incomplete because at the very least 12 is also still affected from our experience. Therefore as long as the minimum version for either Specs or implementations is Java 11 or 12 and not higher, there should be some form of caveat about Multi-Release-JAR usage in combination with JPMS.

tomas-langer commented 3 years ago

Is there a plan to upgrade minimal Java version requirement? Considering Java 8 is end of life, if we base Jakarta 10 on Java 11, we do not need to have multi-release jars, and can fully utilize JPMS using module-info.java.

keilw commented 3 years ago

That's a good point, I am also not entirely sure, if OpenJDK some day pruned or eliminated the ServiceLoader mechanism via META-INF\services only to use definitions in module-info.java? From what I know, if you define them as provides in the latter you should not need to define the services folder as well (unless you need a fallback for JDKs before 9)

Should any project plan to use "fancy new stuff" like records, etc. (maybe not all of it likely for an API but who knows what they plan to use) then even with a minimum Java SE version like 10, 11 or 12 there could still be a temptation and need to use these via Multi-Release-JAR although I must admit, for specs there may not be such a benefit, given that for the time being I don't think a spec may offer element X but Y only if you are on Java 16 or above? ;-)

anthonyvdotbe commented 3 years ago

tl;dr Java SE 11 for module descriptors (and Java SE 8 or 11 for source code, but that question is irrelevant w.r.t. modules)

@keilw I don't see any evidence that proves there are unresolved JDK issues w.r.t. the module system and/or MR JARs:

@tomas-langer MR JARs are not a prerequisite for Java SE 8-compatible modular JARs: the module-info.class can simply be placed in the JAR's root directory

I don't think a spec may offer element X but Y only if you are on Java 16 or above?

This question is irrelevant, because the JAR spec itself doesn't currently allow it:

The public API exported by the classes in a multi-release JAR file must be exactly the same across versions [...] A future release of this specification may relax the exact same API constraint to support careful evolution.

(edit: @keilw I'm disappointed by your response and will not engage any further in this discussion)

keilw commented 3 years ago

@anthonyvdotbe Thanks but indriya#346 is meaningless and I already closed it as invalid. Frankly I don't care if the JDK team did not do their homework or papertrail. What I and users care is that it works and it doesn't between Java 9 and 12, there is neither a JDK 11.0.2 this works with (we tested it, it fails with every JDK 11 up to jdk-11.0.8) nor any released Java 12, it was only fixed from 13 and they simply forgot or were too busy with other things to backport it. Or it was only made available to paying customers but not the common OpenJDK builds available under AdoptOpenJDK or similar.

You are right however, that only adding a module-info unless new services or packages only making sense for a higher JDK (unlikely for a spec but an implementation like Indriya is free to support certain functionality only when it makes sense for that JDK version, the JSR 363 RI also did not support LocalDateTime or Temporal while the then inofficial forward-port for Java 8 did) require you to define more than one module-info in a Multi-Release-JAR structure, it can be placed in the top-level and Java 8 applications will just ignore it. What you quoted from a JEP first of all isn't a binding specification, the JEP is merely a feature request that may or may not be done and the actual Java specifications may be very different from what the spec writes about Plus it sounds reasonable for the public API of Jakarta Specifications, but this ticket is not only about (Jakarta) Specification documents and you may well see an E.class in an implementation that is specific to Java 12 or 16 e.g. it may be using a record that makes no sense in any of the prior Java versions. And again there is no need to declare the same class as an empty shell or throw an UnsupportedOperationException in an implementation if that feature makes no sense, don't offer it before the JDK version that does.

lukasj commented 3 years ago

Requiring automodules for Jakarta EE APIs which expose those names

This should be no-go for spec projects. There are more problems with them but the one I mean here is that jlink does not support them. Even though that can be seen as not-an-issue from the EE/appserver perspective, it can be problem in various standalone implementations and there were users who were quite loud about this in few projects (ie activation can be an example) and Jakarta EE definitely wants to allow and also support usage of various specifications out of the EE container.

Establishing behaviors or conventions around usage of module mechanisms in a Jakarta EE environment (for example, special behavior specifications around service loading)

open module propagation to allow reflection access is another thing. What I as an end user want is to open pkg.entities to jakarta.persistence and let the persistence API figure out to which implementation this open should be propagated to. I do not want to rely on particular persistence implementation be it EclipseLink or Hibernate or whatever else. This can be generalized as sth like To allow reflection access from the CI to user defined classes, user code must be open to specJar which propagates this openess to an implementation found by lookup mechanism defined in spec (where user defined classes can be ie entities, jaxb/jsonb annotated classes etc)

Is there a plan to upgrade minimal Java version requirement? Considering Java 8 is end of life,..

Do not take me wrong from the text bellow - I vote for SE 11 as the base should my vote be the binding one ;-) While Java SE 8 is EOL, support for it is going to end by December 2030, so in almost 10 years from now. I'd be personally very happy to jump directly over to SE 17 right now all over the place but I think, EE 10 should still run on 8 and min Java SE version should move to 11 in Jakarta EE 11. (Should there be any 10.X releases, all of them should keep the same min Java SE level as initial 10.0 version - but I think this is clear).

if OpenJDK some day pruned or eliminated the ServiceLoader mechanism via META-INF\services only to use definitions in module-info.java? From what I know, if you define them as provides in the latter you should not need to define the services folder as well (unless you need a fallback for JDKs before 9)

https://docs.oracle.com/en/java/javase/11/docs/specs/jar/jar.html#modular-jar-files gives clear answer to that:

If the modular JAR file is deployed on the class path then it behaves as if a non-modular JAR file.

Which, in the other words means that module-info is ignored if the jar is on the classpath. So as long as class-path mode is to be supported, META-INF/services must be present.

Should any project plan to use "fancy new stuff" like records, etc.

At the spec project level, usage of "fancy new stuff" should be discouraged (or not recommended) - but probably not strictly prohibited, unless it comes from an LTS Java SE version (ie support for SE 15 would not be recommended, for SE 17 it would be OK). My thinking here is that implementations/vendors should not be forced to provide support for possibly changing features. If they want to support them in their implementations, they can do so even under current rules.

the module-info.class can simply be placed in the JAR's root directory

or under the versioned directory. It is possible to have slightly different descriptors for different SE versions. This is defined at https://docs.oracle.com/en/java/javase/11/docs/specs/jar/jar.html#modular-multi-release-jar-files - this also proves that the statement JPMS and Multi-Release-JAR mechanism are incompatible is false as long as defined rules are followed.

I'm not sure it is feasible to have this completely covered, defined and implemented in EE 10. But it would be definitely good to start with spec and CI can support JPMS by following TBD rules/recommendations and switching it over to spec must and CI can support JPMS in EE 11 together with further adjustments and bumping up min SE version to 11 there. It would be nice to say must also for the CIs in EE 11 but I'm afraid there will be implementations not willing to jump on the JPMS train.

nipafx commented 3 years ago

Hi there, sorry to barge in but I heard people are discussing modules and I'm always up for that. :) Caveat: I don't know the Jakarta EE space well, so I may be missing context - let me know if you think I do.

A few random replies:

We need to clearly define the requirements for supporting JPMS

👍🏾 Maybe this helps. (Note that it has no official character and didn't catch on, but I still think it's good. 😊 )

Requiring automodules for Jakarta EE APIs which expose those names

Technically, the automatic module name is only that: a name for the JAR if it's used on the module path. But socially, it also signals to users that the JAR works fine on the module path. I recommend to only define a name once that has been established.

It may be a special niche but based on Bugs at least until Java 13 not fully addressed (so if the minimum JDK version was 11-13 there is a great risk of that) JPMS and Multi-Release-JAR mechanism are incompatible and may cause serious problems if used together without safety-measures.

As far as I can tell, this analysis is based on a malformed JAR (see my comment in unitsofmeasurement/indriya#346) and unrelated jdeps and Maven issues. I don't think it holds up.

I am also not entirely sure, if OpenJDK some day pruned or eliminated the ServiceLoader mechanism via META-INF\services only to use definitions in module-info.java?

I have no particular insight into plans for the service loader, but I'd be extremely surprised by such a change as it would severely neuter the class path. So unless the class path itself is going away (would be equally surprising), I wouldn't worry about this. And @lukasj got it right re service declarations: If a JAR is supposed to work on class path and module path, it needs to define services in META-INF\services and module-info.java.

What I and users care is that it works and it doesn't between Java 9 and 12, there is neither a JDK 11.0.2 this works with (we tested it, it fails with every JDK 11 up to jdk-11.0.8) nor any released Java 12, it was only fixed from 13 and they simply forgot or were too busy with other things to backport it. Or it was only made available to paying customers but not the common OpenJDK builds available under AdoptOpenJDK or similar.

Re fixes in 13 not being backported in 12, that's because 12 is no LTS version. As far as I can tell nobody in the OpenJDK community is backporting fixes to it and neither does anybody offer commercial support for it.

At the spec project level, usage of "fancy new stuff" should be discouraged (or not recommended) - but probably not strictly prohibited, unless it comes from an LTS Java SE version (ie support for SE 15 would not be recommended, for SE 17 it would be OK). My thinking here is that implementations/vendors should not be forced to provide support for possibly changing features.

I may well have misunderstood the last sentence, so this might be a non-sequitur, but I want to point out that only preview features (enabled with --enable-preview) will change between releases. Once they're out of preview (e.g. text blocks in 15), they're set in stone regardless of whether that version is LTS or not. More to the point LTS is a commercial concept that the JLS doesn't give two Guy Fawkes about. 😁

keilw commented 3 years ago

@nipafx Thanks for your input here. I just literelly at this moment saw the mail, that DWX' 21 also has to happen remotely, so while I anticipate your JDK talk, we (including @thodorisbais, @ivargrimstad, you and myself) won't meet in person then, because after the recent Corona "Emergency Break" in Germany they certainly did not see a chance to hold it in person, especially not in the home town of Markus Söder ;-/

You made most of the good points here, especially about --enable-preview which the initial JSR 376 spec (that remained unchanged ever since a vast number of us here who were also in the JCP EC back then voted against it in 2017 and some, but only minimal changes were applied but enough to get us approve it in the end) did not even know back then, but especially problems and bugs related to jdepts or jlink like JDK-8207162 are going to be a problem as long as the mimimal Java version stays at 9-11 or even 12.

@anthonyvdotbe Sorry to dissapoint you, but I was also quite surprised to even learn of your ticket #174 which only @kwsutter had ever exchanged a few thoughts with until @starksm64 linked it here and some had a look at it. I was quite actively involved in shaping a minumum level of modularity and JPMS in Jakarta EE 9 already, but there were some compromises (as everywhere also in other specs especially in the JDK itself ;-) and a few specs or APIs that did not feel ready at the time especially CDI while others had done that already. It seems you made at least one commit to microprofile, have you ever tried approaching it about JPMS because while 2/3 or more of Jakarta EE specs and APIs already support at least Automatic-Module-Name since Jakarta EE 9 or earlier, there is zero evidence the official MP APIs ever got a single JPMS definition of their own, the only one seems to be added later by projects like Helidon (@lukasj probably knows a lot more about that) and unfortunately not even some key stakeholders to Eclipse MicroProfile are always completely aware of using JPMS and problems that may arise if you do it wrong, especially Split Packages? Did you ever raise those kinds of tickets with MicroProfile like you did here and we just don't know about or did you not suggest it there @anthonyvdotbe, I think while I cannot promise it'll succeed with every single contributor you should try to raise awareness there if you care about this topic.

pron commented 3 years ago

support for it is going to end by December 2030, so in almost 10 years from now

Support is going to continue at least until December 2030. Oracle might decide to extend it further as long as there are enough paying customers.

The question is, what does this have to do with support for Java 8 in new versions of libraries/specifications? Java 8 is essentially EOL and has been very much discouraged for new projects for a while, now. It is now in pure legacy maintenance mode, and new specifications targeting it might confuse people further about this.

starksm64 commented 3 years ago

Is there a plan to upgrade minimal Java version requirement? Considering Java 8 is end of life, if we base Jakarta 10 on Java 11, we do not need to have multi-release jars, and can fully utilize JPMS using module-info.java.

The expectation is that at least Java 11 will be required. This is being tracked in #331 where the question of Java 17 support is also raised.

keilw commented 3 years ago

@pron For completely new services I agree and I also helped a customer introduce a green-field system based on Java 11+ around 2 years ago, but right now I have another case where "Legacy" systems like Tibco, CORBA or even Host systems are involved in a very big company and none of those are being replaced before at least the mid 2020s. Thus they add new services using Java 11 and Jakarta EE or Spring Boot, etc. but they still have those old systems and for SOAP or other protocols many don't get touched until eventually they might be replaced by something like a new REST based API and only then when all the services are upgraded, the last Java 8 client or server is going to disappear. And keep in mind, Java 8 has a longer Extended Service guarantee than even the upcoming Java 17, see Oracle Java SE Support Roadmap, so some customers including the ones I deal with at the moment are more likely to switch from 8 to 23 in Fall 2024 when that seems like the next LTS following a 3-year cycle.

@tomas-langer For the spec the need for multi-release-jar support could be close to zero, for implementations I would not outrule that however as I cannot speak for all the projects and their project leads, that we may only recommend on a platform level but it's up to each of them and their products what they do, so it can't be outruled. Even less for applications consuming it, #331 had a good case by someone who said they already use Records, thus unless they force all of their users of the system to immediately upgrade to Java 16 or 17 they may need a multi-release-jar while the spec or even implementation could do without. And as @lukasj mentioned a little earlier, if the module-info was ignored in that case, the module could be lost unless you also provide an Automatic-Module-Name as a last resort.

pron commented 3 years ago

@keilw Java 8 will be supported for as long as Oracle deems it worthwhile; could be 2050; could be 2150. The point is that while maintenance releases of existing specifications, like Jakarta EE 9, might want to support Java 8 until, say, 2045, this shouldn't affect the minimum required version for new specifications, like Jakarta EE 10. I mean, you can choose to target Java 8 if you like, but my point is that Oracle's legacy support for 8 shouldn't impact that decision one way or another. Java 8 should no longer be used for any new projects, and new specification versions can safely (and probably should) choose not to support it.

keilw commented 3 years ago

@pron Sure but then it becomes expensive. I worked at BEA just before Oracle purchased it and many of those support plans for the Middleware still exist or were combined with what Oracle had. And we had Weblogic 4 customers (2007 WLS 10 was released, so 4 existed since 1999) who needed support by the Professional Support team I helped and paid somewhere between a single and double-digit Million $ amount per year for that, so yes, if you are happy to pay you could use it until the end of times.

pron commented 3 years ago

My point is just that Oracle's (possibly eternal) support period should not play a factor in the decision of which version to support. Java 8 is EOL for new work and there's no need to support it in new spec versions.

starksm64 commented 3 years ago

My point is just that Oracle's (possibly eternal) support period should not play a factor in the decision of which version to support. Java 8 is EOL for new work and there's no need to support it in new spec versions.

Agreed. The discussion on the minimal Java SE version should occur on #331. Currently there is no expectation that the Java SE version will be less than 11.

lukasj commented 3 years ago

My point is just that Oracle's (possibly eternal) support period should not play a factor in the decision of which version to support.

Point taken. My concern is "What's next, after EE 10 gets out, and when?" What I would expect from the Platform project is at least rough, say mid-term, schedule for at least current + 1 releases in terms of supported Java SE versions. I could have probably missed or haven't heard ie sth like: Within 6 months of new Java SE LTS release X there is new Jakarta EE Platform release with Java SE X set as a minimum supported Java SE version. This version of Jakarta EE allows changes breaking backwards compatibility rules. and Every 6-12 months there may be an update release for the latest Jakarta EE version available. This version does not allow breaking changes and requires strong backward compatibility with the EE version the update is based on. That would send clear message not only to spec projects, which can then plan features for the platform as a whole and/or their updates accordingly, but also to the community/customers wrt when there will be an update/new major version and what its basic requirements are going to be.

keilw commented 3 years ago

This has been a little silent, maybe it'll gain more speed after 9.1 is out, but one important finding after a little "goose chase" we finally got an answer to what happened in unitsofmeasurement/indriya/issues/301 although the answers came from another completely unrelated issue. The underlying JDK issue JDK-8235229 was discovered in Java 11 but seems to affect all from Java 9 up to 15 and it was only jut recently fixed in Java 16, but no evidence of a backport to at least the LTS version 11 if that's even possible with such a great distance?

Meaning if a Jakarta EE application defines or consumes a modular, multi-release JAR it is at risk of this problem and may lose the module-info or (if present) fall-back into an existing Automatic-Module-Name. Providing both is what we did to fix this in JSR 385 and unless that fix was provided for Java 11 the only sustainable approach would be to compile and run your application with Java 16 or above (also should be set as release of the target app)

anthonyvdotbe commented 3 years ago

tl;dr JDK-8235229 is irrelevant, both to this issue and #331

JDK-8235229 was a compilation-only issue: when using the --release parameter, javac didn't treat multi-release JARs as such, and only considered their top-level directories.

Since the JAR spec specifies that:

The public API exported by the classes in a multi-release JAR file must be exactly the same across versions

it had a negligible impact (which is why it wasn't reported until after the release of Java SE 13 and is unlikely to be backported). The only reasonable scenario (i.e. a scenario that only involves spec-compliant multi-release JARs) I can readily think of is the one in the report: a modular multi-release JAR that does not contain a module-info.class in the top-level directory, but does contain one in the 9-versioned directory. In this case, the JAR is incorrectly treated as an automatic module, which might result in erroneous - but harmless - warnings being issued. (To eliminate those warnings, one can either compile with JDK 16+ and specify the appropriate --release parameter, or compile with the appropriate JDK and not specify the --release parameter.)

keilw commented 3 years ago

Well failed compilation is bad enough, so there needs to be a warning in certain documents (probably user guide at the very least) so even if the combination of modules and multi-release-JARs may still be rare people are aware and know what to do. With Java SE 16 final they can find a way around it as long as the application has no problems with Java 16. And #331 must go up to Java 16, otherwise they could not use it yet if the compatible Java version range was too narrow.

It's all but harmless if the module-info from such affected JARs do contain important definitions like service and others like hiding packages that should be private and internal (I leave that to e.g. @lukasj who was very vocal about module-info vs. Automatic-Module-Name here to judge in more detail) all of that is lost in a non-modular fashion. If the MANIFEST also contains a fall-back Automatic-Module-Name, then at least that name can be resolved, but services if defined in META-INF/services as a fallback may take over and the package protection is lost, that does not exist for automatic module names. If the MANIFEST does not contain that protection, then the JAR file name could result in a completely different auto-derived module name instead of the one in the module-info.

According to a JUnit committer parts of JUnit 5 like junit-platform-commons use multi-release JARs at least since JUnit platform 1.1, therefore tests could be affected, and https://github.com/DKE-Data/agrirouter-sdk-java/issues/146 hints, Log4J2 also uses MRJ (it does at least log4j-core after 2.13 or even earlier) , so more and more popular libraries do. Those are certainly not the only onese and developers of a Jakarta EE application cannot be forced to check or look into every dependency they use, if that uses Automatic-Module-Name (which is not affected) or has a module-info and on which level(s) those are.

This may affect EE4J artifacts (if they are not able to build against Java 16+ yet), implementors of Jakarta EE when they build their products, and of course consuming developers alike if they come across at least one such JAR. It's nice, that they found a solution for https://github.com/DKE-Data/agrirouter-sdk-java/issues/146 but if simple upgrading to a new Spring version may not be an option or even to Java 16 yet because they use some other library that is not yet compatible with 16+ then they are stuck or at least delayed with a build problem. So certainly not harmless or something to brush away, it must be properly documented and not ignored. Not all solutions are built in "Cloud Dreamland" where they simply pull a new Docker image and everything is fine, even in a Hybrid or dedicated On-Premise environment or in large corporations dependencies cannot always just be replaced, or they need to be vetted and approved first.

Trying to refrain from multi-release JARs for the Jakarta specs and APIs themselves unless there is a non-deniable argument for it also seems a good suggestion. At the moment none of them do, so if they already declare a module-info these are usually in the root folder, but the spec allows both and third-party libraries or their individual methods to build them cannot all be changed or controlled, so one may end up with an affected modular multi-release JAR.

anthonyvdotbe commented 3 years ago

tl;dr I agree that JDK-8235229 is relevant, in the sense that Jakarta EE should not produce any such JARs (by requiring a module-info.class file to be present in the top-level directory)

About the lack of Automatic-Module-Name: you're right, it will cause compilation errors if the filename-derived module name doesn't match the one in the module descriptor. About META-INF/services being absent or inconsistent: I'd argue that's a malformed JAR. If you have multiple module descriptors in an MR JAR, their provides clauses must be the same. So since META-INF/services is really just "pre-modular provides clauses", it should be consistent with any module descriptors' provides clauses as well. About all packages being exposed: you're right, this might cause an inconsistency, where compilation succeeds but an exception is thrown at run-time. However, it's likely that IDEs handle this kind of MR JARs correctly already, thereby preventing this from happening in practice.

So again, the issue can only occur in a very specific case: a modular multi-release JAR that does not contain a module-info.class in the top-level directory, but does contain one in the 9-versioned directory. And for it to cause trouble in practice, even more conditions must be satisfied. Either way, neither junit-platform-commons (which has one in the top-level directory) nor log4j-core (which doesn't have one in the 9-versioned directory) are problematic.

Also, there are several ways to deal with it. As mentioned, one can either compile with JDK 16+ and specify the appropriate --release parameter (this does not require to run Maven itself with such JDK), or compile with the appropriate JDK and not specify the --release parameter (I'd expect this to be a trivial change in most cases). Another option is even simpler: do nothing. The worst-case scenario here is that some code relies on non-exported packages and that none of the tests actually test this code. But at this point there's so many conditions that must be satisfied, that I doubt this will ever occur in practice, especially in the context of Jakarta EE.

keilw commented 3 years ago

No META-INF/services is not even required in a modular world, take Helidon and the colleagues here can probably tell even more which provides io.helidon.config.spi.ConfigParser with PropertiesConfigParser; and has no trace of a META-INF/services doing the same. Now Helidon does not use a multi-release JAR but Jakarta EE cannot control or enforce what any given third party library does out there and issue reports like the mentioned (only as brief example) show these happen in the "Cloud Native Java" World including Micronaut, Spring, MicroProfile or all the other "Microframeworks" most of which also build on top of Java or Jakarta EE.

lukasj commented 3 years ago

No META-INF/services is not even required in a modular world

Jakarta MUST keep compatibility with the classpath mode. In that world, META-INF/services are mandatory. Wrt Helidon, it started to create entries in META-INF/services during the build based on the content in module-info (there is a maven plugin which does that)

keilw commented 3 years ago

@lukasj Thanks for the input. I guess where backward-compatibility of the API even down to Java 8 is required for the time being (likely up to another decade) Jakarta EE has higher backward compatibility requirements than some of the "Microframeworks" may have.

Of course the module-info also does other things especially hiding internal packages with local helper classes used only by the system and not exposed anywhere. It may be a very rare case as well, but if in a multi-release JAR there's a need for more platform-specific internal packages or classes, access to those can be regulated in the module-info in various ways also ensuring that ClassA was only visible to ClassB and nothing else. Falling back to a root-level module-info or even worse Automatic-Module-Name those contstraints are lost and classes or modules and packages not intended to be used on the outside could be visible.

lukasj commented 3 years ago

My comment is not necessarily related to backwards compatibility as such. As long as Java SE itself supports class-path, there is no way for jakarta APIs to deny people putting APIs there effectively bypassing all constraints defined in module-info regardless on where exactly the descriptor is located.

keilw commented 3 years ago

Of course the APIs should and while it is up to what individual vendors and their compatible implementations do (if they force them to upgrade to Java 17 it's their call) the former RIs like Glassfish may also go a little softer here and e.g. try to avoid multi-release JARs or offer enough backup mechanisms if they were not used yet.

lukasj commented 3 years ago

the former RIs like Glassfish may also go a little softer here and e.g. try to avoid multi-release JARs

6.1 contains few MR Jars already (with module-info in place - in jar's root), 6.0 as well, and I haven't heard about any issues on 11 caused by this yet

keilw commented 3 years ago

I think if you keep module-info in the root that's normally not affected, but in more complex systems there may well be multiple module-info files in addition to that and those may e.g. fall-back to the default if you have it. And it is spec-compliant to "also" put the module-info into a Java 9 folder.

A module descriptor is generally treated no differently to any other class or resource file. A module descriptor may be present under a versioned area but not present under the top-level directory. This ensures, for example, only Java 8 versioned classes can be present under the top-level directory while Java 9 versioned classes (including, or perhaps only, the module descriptor) can be present under the 9 versioned directory.

Even suggests that might be the preferred way. At least it's possible and we cannot prevent the other third-party developers or end users from using either way depending on which other needs they have. I believe Indriya (JSR 385 RI) may have used a module-info per version primarily due to the Maven Toolchain Plugin which currently seems the safest and best working way to have true multi-release JARs (8+1 is only dual-release ;-) I could also look it up but @lukasj or @arjantijms can you briefly tell which of the build and plugin approaches you used there? I recall Moneta, the JSR 354 RI uses more or less the same we saw in the JSON specs even under Java EE 8 (therefore it also has the module-info in the root), but I don't think that would work for 3 or more releases rather than just 2.

Of course JSR 385 has very different target environments, it should run anywhere from Rasperry Pi (even the Pico, if Java still runs there?) to large Data Centers in the Cloud. Its predecessor JSR 363 RI was the only known case from the "Java SE side" to ever pass and run on the Java ME 8 Embedded platform other than the contents of Java ME Embedded themselves. It also runs on Android (both Java especially after the SCOTUS ruling and Kotlin ;-) and other embedded systems. Which is why I said in other threads, you should not judge a spec "by its cover" without knowing enough about its background or context. Other libraries may be highly customized to particular platforms and while there's more to expect for Apple in Java 17, ARM support already got added to Windows 10, so you might see a Java 10 or higher directory in MR JARs for such cases, too.

anthonyvdotbe commented 3 years ago

the issue can only occur in a very specific case: a modular multi-release JAR that does not contain a module-info.class in the top-level directory, but does contain one in the 9-versioned directory.

I invite everyone to find an actual library like this. (I'm not saying there aren't any, just that I predict it won't be easy to find one, let alone one that is somewhat popular.) Also note that there's likely tools/libraries out there that support modules, but don't support MR JARs yet. So it's equally likely that module descriptors are being placed in the top-level directory already in order to accommodate those. And as explained before, the implications in practice are negligible (which is why it went unnoticed until after Java SE 13, was classified as a P4 bug, and there hasn't been any fuss about it until 3 days ago).

keilw commented 3 years ago

Well it's not up to the Jakarta EE WG to "find libraries" and the spec allows both, plus there can be multiple versioned directories (the example only mentions one, but the bug 301 filed gainst Indriya earlier also was raised for a true multi-release JAR) with more than just one, that I agree is probably even more rare but not impossible and there are so many JDK versions between 9 and 15 all of which could face this. The correct cause of 301 was just identified around 3 days ago, but the actual issue as small as the JDK team may consider it was known much longer and 301 was also filed almost a year ago. And of course the one you filed was also a P4 or less because it never even occured in real life and unlike 301 affects only those above Java 12 who wish to use CompactNumberFormat.

And large companies have large application lifespans and complex distributed systems, they don't just switch to a new JDK because Oracle or Adoptium say so and make it available. They may only start using Java 11 now and if that's the minimum level for Jakarta EE 10 stay there for another few years. They don't touch or upgrade hundreds or thousands of applications in the enterprise, they ma have a business requirement and as a side-effect also upgrade the JDK while others remain until the lifespan of the JDK expires or the whole project or product might be superceded and discontinued. Especially with Java 11 being an LTS (Java version history shows this well also for a few others like Zulu) many companies will only start switching to 11 in a few years and since more changes than even 11 brought may introduce far more problems for their apps not even dare to switch before 2027 or later, and many of them probably never even use 17 because they would rather wait for Java 23 to be the next likely LTS after that.

lukasj commented 3 years ago

this is going nowhere. The responsibility of the WG/platform group should be to say that it wants/does not want to support JPMS and if it wants to support it, then define requirements for the specs to be satisfied in order to be included in the platform X.Y.Z and approximate time-line for delivering full featured JPMS support. I don't think it is feasible to have everything ready within one release. I think it would be sufficient to include this as a (strong?) recommentation in the platform architecture document @ivargrimstad created.

Platform may also require support for JPMS by spec's CIs at some point in the future.

I can imagine that for EE 10 requirements on included specs are:

While this certainly does not capture everything, it should be enough to allow people using spec APIs on JPMS and give community option to come up with new CIs fully utilizing the module system.

If some spec decides (and is allowed to) support multiple newer SE versions through MR jar beyond the Platform defined minimum version, it should be responsibility of that spec/corresponding CIs/platform CIs to resolve any encountered issues - either by not including newer SE version specific support, compiling with latest JDK (fine as long as running on min required platform defined SE level is supported) or working with JDK/other dependencies teams on fixing issues there. Platform project itself as such should not care about these "implementation details" to certain extent.

At the end of the day, what I - as an end user - want in order to develop my app for the Platform X.Y.Z at some point in the future is to define my app as:

module org.eclipse.platformdemo {
    requires jakartaee.platform;
    requires jakarta.xml.bind;
    requires my.lib;
    exports my.jaxb.classes;
    opens my.jaxb.classes to jakarta.xml.bind;
    ....
}

where jakartaee.platform comes from jakarta.platform:jakarta.jakartaee-api:X.Y.Z artifact, is set to provided scope and is defined ie as:

module jakartaee.platform {
    requires transitive jakartaee.web;
    requires transitive jakarta.persistence;
    ....
    // optional parts
    requires static jakarta.xml.bind;
    ....
}

This artifact/module contains spec APIs ONLY; no implementation classes should be allowed to guarantee vendor-neutrality (as it is with current version of the jakarta.jakartaee-api artifact); should this artifact be put on the classpath, the behaviour is exactly the same as it is today.

Now I want to build my app and "run" it somewhere. Let's say there is vendor V, who opts-in to support JPMS and provides CI for Plarform X.Y.Z. This vendor defines its own implementation of the jakartaee.platform module through let's say com.vendor:jakarta.platform:X.Y.Z artifact like ie:

module jakartaee.platform {
    requires transitive jakartaee.web;
    requires transitive jakarta.persistence;
    ....
    // we contain optional parts
    requires transitive jakarta.xml.bind;
    ....
    // implementations we use
    requires transitive com.sun.xml.bind;
    requires transitive org.eclipse.persistence.moxy;
    ....
}

When my app is deployed into such environment, all modules are properly resolved and my application just runs. Vendor V may also allow deployment which completely ignores modules through some option. There also can be other vendor W, who did not opt-in to support JPMS - such vendor only needs to make sure that all JPMS descriptors are ignored and when I take my app and deploy it into W's environment, the app runs exactly the same way as today.

...just my 2¢...

keilw commented 3 years ago

That's precicely what I suggested 2 days ago: https://github.com/eclipse-ee4j/jakartaee-platform/issues/329#issuecomment-838659971 and I don't think we need countless more arguments for and certainly none against it here. It was on the Agenda for the platform call but this time we did not get there, hopefully in one of the next weeks. Thanks @lukasj for sketching something out, guess it could be used in the right document. P.s.: I suppose with "reliance on automatic module name is not allowed" you mean the "fully-automatic" one if nothing is declared in the MANIFEST either?

lukasj commented 3 years ago

P.s.: I suppose with "reliance on automatic module name is not allowed" you mean the "fully-automatic" one if nothing is declared in the MANIFEST either?

I originally wanted to say: NO Automatic-Module-Name in the manifest. The difference for most specs which do not have anything yet is whether they add one line to manifest or create new file having ~10 lines if I don't count license header - in terms of time spent on this, how big difference it is? 10 minutes? OTOH when we come down to implementation, it may depend on minimum supported Java SE version by the platform itself and possible issues we may encounter in JDK or tools we use. Therefore I did not want to be that strong on that requirement yet. This can be made strong requirement in the next iteration/version. I can also imagine that first iteration is platform-10-M1 (AMN in manifest is allowed) and the next is platform-10-M2(AMN in manifest is forbidden)

btw: "reliance on automatic module name is not allowed" where automatic-module is defined by https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/module/ModuleFinder.html#automatic-modules

starksm64 commented 2 years ago

For EE10 we decided on a minimal adoption strategy for API jars with no binding behaviors. This is now an EE11 issue if there are real requirements around supporting JPMS in deployments.