From david.lloyd at redhat.com Wed Jan 8 17:57:08 2025 From: david.lloyd at redhat.com (David Lloyd) Date: Wed, 8 Jan 2025 11:57:08 -0600 Subject: `requires static` versus service binding Message-ID: It is not uncommon for a library to contain a provider for a service where the service resides in an optional dependency. It is also sometimes desirable to use a service from an optional dependency. In JPMS, we can use `requires static` to indicate that the library will function without the dependency being present. We can declare that we use or provide a service from the optional dependency. Compilation will complete successfully in this case, because the descriptor is valid. However, at run time, the module will fail to resolve if any provider or uses comes from a module that is not present when the layer is resolved. This is not desired behavior, because the user has already opted in to and indicated that the dependency in question is optional, and should not cause a run time problem if not present. The current behavior is inconsistent between compile and run time, and should be revisited. -- - DML ? he/him -------------- next part -------------- An HTML attachment was scrubbed... URL: From alan.bateman at oracle.com Wed Jan 8 18:25:29 2025 From: alan.bateman at oracle.com (Alan Bateman) Date: Wed, 8 Jan 2025 18:25:29 +0000 Subject: `requires static` versus service binding In-Reply-To: References: Message-ID: <34f95d77-c081-4d26-b61c-adab76e151c0@oracle.com> On 08/01/2025 17:57, David Lloyd wrote: > It is not uncommon for a library to contain a provider for a service > where the service resides in an optional dependency. It is also > sometimes desirable to use a service from an optional dependency. > > In JPMS, we can use `requires static` to indicate that the library > will function without the dependency being present. We can declare > that we use or provide a service from the optional dependency. > Compilation will complete successfully in this case, because the > descriptor is valid. > > However, at run time, the module will fail to resolve if any provider > or uses comes from a module that is not present when the layer is > resolved. This is not desired behavior, because the user has already > opted in to and indicated that the dependency in question is optional, > and should not cause a run time problem if not present. > You can find previous discussion on this topic in JDK-8299504 [1] and this mailing list [2]. -Alan [1] https://bugs.openjdk.org/browse/JDK-8299504 [2] https://mail.openjdk.org/pipermail/jigsaw-dev/2023-April/thread.html#14846 -------------- next part -------------- An HTML attachment was scrubbed... URL: From forax at univ-mlv.fr Wed Jan 8 18:35:04 2025 From: forax at univ-mlv.fr (Remi Forax) Date: Wed, 8 Jan 2025 19:35:04 +0100 (CET) Subject: `requires static` versus service binding In-Reply-To: References: Message-ID: <1014041460.45728210.1736361304919.JavaMail.zimbra@univ-eiffel.fr> Hello, It depends how the service is resolved, i.e. if there is a fallback strategy or not. The mechanism of "require static" is not restricted to work only with services. It's a mechanism to express the fact that you can have a runtime dependency which is present or not. A module that required a static module should have a code that deal with the fact that the dependency may not be present at runtime. By example, jackson has a mechanism of runtime extensions, so it works with different versions of the jdk using the same code, because the code of jackson can check at runtime if an extension is present or not. regards, R?mi > From: "David Lloyd" > To: "jigsaw-dev" > Sent: Wednesday, January 8, 2025 6:57:08 PM > Subject: `requires static` versus service binding > It is not uncommon for a library to contain a provider for a service where the > service resides in an optional dependency. It is also sometimes desirable to > use a service from an optional dependency. > In JPMS, we can use `requires static` to indicate that the library will function > without the dependency being present. We can declare that we use or provide a > service from the optional dependency. Compilation will complete successfully in > this case, because the descriptor is valid. > However, at run time, the module will fail to resolve if any provider or uses > comes from a module that is not present when the layer is resolved. This is not > desired behavior, because the user has already opted in to and indicated that > the dependency in question is optional, and should not cause a run time problem > if not present. > The current behavior is inconsistent between compile and run time, and should be > revisited. > -- > - DML ? he/him -------------- next part -------------- An HTML attachment was scrubbed... URL: From josiahnoel at gmail.com Wed Jan 8 18:39:41 2025 From: josiahnoel at gmail.com (Josiah Noel) Date: Wed, 8 Jan 2025 13:39:41 -0500 Subject: `requires static` versus service binding In-Reply-To: References: Message-ID: We also raised the same issue a while back. https://mail.openjdk.org/pipermail/jigsaw-dev/2023-April/date.html#14853 A possible solution that was discussed was to have a mechanism to have multiple modules in a single jar. (But obviously that hasn't been implemented yet) We managed to solve it in our library via a circular plugin dependency. (Library A has a dependency on Plugin B which depends on an older version of library A to provide A's functionality to Library C) It's pretty painful to setup/modify, but if you don't expect the spi implementation to change that much it works I guess. Even so I also wish there was an easier way to provide optional services so we don't have to go through that whole circular song and dance. On Wed, Jan 8, 2025, 12:58?PM David Lloyd wrote: > It is not uncommon for a library to contain a provider for a service where > the service resides in an optional dependency. It is also sometimes > desirable to use a service from an optional dependency. > > In JPMS, we can use `requires static` to indicate that the library will > function without the dependency being present. We can declare that we use > or provide a service from the optional dependency. Compilation will > complete successfully in this case, because the descriptor is valid. > > However, at run time, the module will fail to resolve if any provider or > uses comes from a module that is not present when the layer is resolved. > This is not desired behavior, because the user has already opted in to and > indicated that the dependency in question is optional, and should not cause > a run time problem if not present. > > The current behavior is inconsistent between compile and run time, and > should be revisited. > -- > - DML ? he/him > -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.lloyd at redhat.com Wed Jan 8 21:33:06 2025 From: david.lloyd at redhat.com (David Lloyd) Date: Wed, 8 Jan 2025 15:33:06 -0600 Subject: `requires static` versus service binding In-Reply-To: <34f95d77-c081-4d26-b61c-adab76e151c0@oracle.com> References: <34f95d77-c081-4d26-b61c-adab76e151c0@oracle.com> Message-ID: On Wed, Jan 8, 2025 at 12:25?PM Alan Bateman wrote: > On 08/01/2025 17:57, David Lloyd wrote: > > It is not uncommon for a library to contain a provider for a service where > the service resides in an optional dependency. It is also sometimes > desirable to use a service from an optional dependency. > > In JPMS, we can use `requires static` to indicate that the library will > function without the dependency being present. We can declare that we use > or provide a service from the optional dependency. Compilation will > complete successfully in this case, because the descriptor is valid. > > However, at run time, the module will fail to resolve if any provider or > uses comes from a module that is not present when the layer is resolved. > This is not desired behavior, because the user has already opted in to and > indicated that the dependency in question is optional, and should not cause > a run time problem if not present. > > > You can find previous discussion on this topic in JDK-8299504 [1] and this > mailing list [2]. > > -Alan > > [1] https://bugs.openjdk.org/browse/JDK-8299504 > [2] > https://mail.openjdk.org/pipermail/jigsaw-dev/2023-April/thread.html#14846 > I see, thanks. The idea that optionality is only an edge case for e.g. annotations (which seems to be these threads' concluding argument against lifting this validation) does not seem to be borne out in the trenches, as can be seen searching google or stack overflow for examples relating to static imports. Additionally, optionality seems orthogonal to service binding, yet they are bound together by this restriction. Sometimes, the tradeoff of having a certain validation is greatly outweighed by the cost in convenience, power, and expressibility. I believe this to be the case here, particularly because I do not believe that there are any cases where the lack of this restriction would cause a worse outcome than having it has caused. I for one have never heard of a single case where a program experienced a problem as a result of a lack of a validation like this even in the old "JAR hell" days. However, it seems that the additional restriction does periodically bite users in general (not just us). It seems hard to justify. Thus I'm inclined to believe that this restriction does not serve any practical benefit, and I hope it can be reconsidered to be respecified as a compile-time-only check. Thanks. -- - DML ? he/him -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.lloyd at redhat.com Wed Jan 8 22:09:31 2025 From: david.lloyd at redhat.com (David Lloyd) Date: Wed, 8 Jan 2025 16:09:31 -0600 Subject: Self-granted permissions do not improve correctness Message-ID: The Java module system features several ways to restrict or grant access to various capabilities. Two of these access permissions can be shown to be of questionable benefit but clear detriment in practice. They are `reads` and `uses`. Both of these permissions, if not granted, cause a run time exception at various points. Both can be trivially self-granted without any restriction to speak of. I have been hard-pressed to identify any incorrect operation, error condition, or security condition which is averted due to the presence of these permissions. However it is not hard to identify problems that they introduce, especially in reflection-heavy frameworks. If these were _privileges_ - able to be granted and revoked based on e.g. lexical scope - then there could be some potential security/bug prevention use in a similar vein as the security manager. But being permissions, once granted, the grant is global and stays in place permanently, thus their usefulness for this purpose is very limited. I'd be interested in a practical example that shows the benefit of either of these permissions to see what I'm missing. Otherwise my inclination would be to request to deprecate and remove these grants (so that `*` reads `*`, and `uses` would only be used for service binding purposes, not run time validation). Thanks. -- - DML ? he/him -------------- next part -------------- An HTML attachment was scrubbed... URL: From alan.bateman at oracle.com Thu Jan 9 07:56:10 2025 From: alan.bateman at oracle.com (Alan Bateman) Date: Thu, 9 Jan 2025 07:56:10 +0000 Subject: Self-granted permissions do not improve correctness In-Reply-To: References: Message-ID: On 08/01/2025 22:09, David Lloyd wrote: > The Java module system features several ways to restrict or grant > access to various capabilities. Two of these access permissions can be > shown to be of questionable benefit but clear detriment in practice. > They are `reads` and `uses`. > > Both of these permissions, if not granted, cause a run time exception > at various points. Both can be trivially self-granted without any > restriction to speak of. I have been hard-pressed to identify any > incorrect operation, error condition, or security condition which is > averted due to the presence of these permissions. However it is not > hard to identify problems that they introduce,?especially in > reflection-heavy frameworks. Core reflection assumes readability [1] so reflection based frameworks don't need to add read edge at runtime. One of the motivations for adding read edges at runtime (with Module::addReads) is code generated at runtime with references to classes/methods/fields in modules that the current module didn't read at compile-time. Is your mail about reflection with method handles? Asking because the access checks done when creating a method handle is the same as bytecode. I assume your issue with `uses` is the check in ServiceLoader. I found Mark's reply to you on this from 2016 [2]. -Alan [1] https://openjdk.org/projects/jigsaw/spec/issues/#ReflectionWithoutReadability [2] https://mail.openjdk.org/pipermail/jpms-spec-experts/2016-December/000524.html -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.lloyd at redhat.com Thu Jan 9 14:29:08 2025 From: david.lloyd at redhat.com (David Lloyd) Date: Thu, 9 Jan 2025 08:29:08 -0600 Subject: Class loader layer registration (8346946) Message-ID: If I have a module layer A containing module X that is registered to some class loader L, *or* a class within the unnamed module of L, and I create a new layer B contains module Y which is also registered to L, and B contains modules which provide services, then once this layer is created, loading services from class loader L will begin to find all service providers in B (even those not in Y) in addition to those in A. This happens dynamically at the time the new layer is created, even if B and A are sibling/cousin layers. This behavior exists today. Sometimes it is desirable to load a plugin (for example) where the module(s) in the plugin provide services but the plugin should be loaded into a layer that is isolated from (i.e. a sibling to) the service-consuming layer, which is generally a private implementation layer or a peer plugin. Note that the service type would be in a parent layer or otherwise findable by both layers. Thanks to the above behavior, this can be accomplished (poorly) today by dynamically generating a layer with a "holder" module, containing one generated class per service provider defined in B which is declared to provide the corresponding service type. Each generated class would contain a `provider` method which accesses the corresponding "real" service provider and instantiates it according to the service loader specification. The "holder" module is then mapped to class loader L, allowing L to then indirectly load the service implementations in the sibling layer. Sometimes it is possible to use a simpler approach where layer B contains a "bogus" empty module which is registered with A. This works when B is defined after A. But this would not generally be the case. This is all unwieldy. The purpose of 8346946 [1] is to allow a simpler way to directly register a layer with a custom class loader for service loading, without defining an extra bogus module or a fake bridge layer. There might be other ways to make this possible than the approach proposed in the current version of the PR [2]. For example, in order to ensure that I control both the class loader and the module layer in question, the protected method on `ClassLoader` could accept a `ModuleLayer.Controller`, ensuring that callers have control over both objects. Other solutions may be possible as well. [1] https://bugs.openjdk.org/browse/JDK-8346946 [2] https://github.com/openjdk/jdk/pull/22905 -- - DML ? he/him -------------- next part -------------- An HTML attachment was scrubbed... URL: From alex.buckley at oracle.com Thu Jan 9 18:04:44 2025 From: alex.buckley at oracle.com (Alex Buckley) Date: Thu, 9 Jan 2025 10:04:44 -0800 Subject: Class loader layer registration (8346946) In-Reply-To: References: Message-ID: <6b6f40fa-67b6-4508-ac69-e30b56b462b0@oracle.com> On 1/9/2025 6:29 AM, David Lloyd wrote: > Sometimes it is desirable to load a plugin (for example) where the > module(s) in the plugin provide services but the?plugin should be loaded > into a layer that is isolated from (i.e. a sibling to) the service- > consuming layer,?which is generally a private implementation layer or a > peer plugin. We do not intend to provide isolation with the module system. We intend to provide strong encapsulation: If the plugin module does not export its provider code, then the JVM prevents access to that code by the service-consuming code (even if it's in the same layer and class loader as the provider code). We expect the framework which loads the plugin to arrange the exports of the plugin module as necessary to achieve this. I am not clear why the framework which loads the plugin is unable to use the JVM-backed access control mechanism to prevent consumers from accessing provider code directly. Alex From david.lloyd at redhat.com Fri Jan 10 15:32:20 2025 From: david.lloyd at redhat.com (David Lloyd) Date: Fri, 10 Jan 2025 09:32:20 -0600 Subject: Class loader layer registration (8346946) In-Reply-To: <6b6f40fa-67b6-4508-ac69-e30b56b462b0@oracle.com> References: <6b6f40fa-67b6-4508-ac69-e30b56b462b0@oracle.com> Message-ID: On Thu, Jan 9, 2025 at 12:05?PM Alex Buckley wrote: > On 1/9/2025 6:29 AM, David Lloyd wrote: > > Sometimes it is desirable to load a plugin (for example) where the > > module(s) in the plugin provide services but the plugin should be loaded > > into a layer that is isolated from (i.e. a sibling to) the service- > > consuming layer, which is generally a private implementation layer or a > > peer plugin. > > We do not intend to provide isolation with the module system. We intend > to provide strong encapsulation: If the plugin module does not export > its provider code, then the JVM prevents access to that code by the > service-consuming code (even if it's in the same layer and class loader > as the provider code). We expect the framework which loads the plugin to > arrange the exports of the plugin module as necessary to achieve this. > I am not clear why the framework which loads the plugin is unable to use > the JVM-backed access control mechanism to prevent consumers from > accessing provider code directly. > For a little bit of background: the access control mechanism by itself doesn't really give us anything that we _need_, per se, in terms of encapsulation. The security and integrity of a Quarkus application for example is not undermined if someone uses a non-supported Quarkus API in defiance of documentation. Having the access control is a "nice to have" for us, in that we can provide some extra steps for the user before they use non-supported APIs, just to make sure it's clear to them what they've signed up for in doing so. That said, we definitely will take advantage of the access control mechanism _as well_ if we can. But for us, isolation is _necessary_ due to the nature of these frameworks and the complexity of their environments. To give a simplified example, we sometimes run into situations where two extensions cannot coexist in one class loader because of various types of conflicts. This can be due to resources in the JAR, services provided, third-party libraries/transitive dependencies which conflict, etc. By isolating these extensions, we bypass these problems completely. We define an environment for our users largely in terms of what APIs are provided by us for the user to consume. This is important because the user is free to bundle any module or JAR they want to include, as long as it is not one of the modules provided by us (note that I'm simplifying some of the nuance for the sake of discussion). But the other side of this coin is that we (or one of our extensions) may want to use a third-party library internally (say, a collections or algorithms library, for example) without making that part of the user's environment. The user should not have to care what modules we use internally, any more than a user cares what private methods exist on our implementation classes. The user might provide their own copy but a different version of the same algorithms library, for example. If we later decide to no longer use that library internally, the user should not know or care that the library has disappeared from our implementation, any more than if we had changed the implementation of a private method. This is in line with our philosophy of encapsulation which strongly emphasizes information hiding. Apart from service binding, isolation works well with the platform module system in conjunction with class loaders. I've experimented with multiple approaches and am able to use the combination of module layer controllers and class loaders to do a variety of interesting things. In fact, more or less everything I have tried has worked well, including (for example) using automatic module descriptors to "modularize" classical JAR-based subsystems based on their Maven dependency information (and other factors). The fact that I can take such a subsystem and turn on module-based access controls, and they just work (other than service loading), is a good sign AFAICT. The extra API surface area that I would need from the JDK to make everything 100% functional is very small, but this change (or something equivalent) is an important part of it. -- - DML ? he/him -------------- next part -------------- An HTML attachment was scrubbed... URL: From magnus.ihse.bursie at oracle.com Fri Jan 10 17:21:51 2025 From: magnus.ihse.bursie at oracle.com (Magnus Ihse Bursie) Date: Fri, 10 Jan 2025 18:21:51 +0100 Subject: `requires static` versus service binding In-Reply-To: References: <34f95d77-c081-4d26-b61c-adab76e151c0@oracle.com> Message-ID: On 2025-01-08 22:33, David Lloyd wrote: > Thus I'm inclined to believe that this restriction does not serve any > practical benefit, and I hope it can be reconsideredto be respecified > as a compile-time-only?check. I agree. I was bitten by this as a Java developer in a hobby open source project, and even if at some point I understood why things where the way they are, I do not remember the reasoning, and I still find it confusing that it did not work as I expected it to, nor what steps I were supposed to take instead to resolve the problem at hand. I understand that this is not a very common problem or a high-priority issue, and I would have accepted that it was down-prioritized to the point that it will take a long time to resolve, but the current "works as intended" approach is still a bit hard for me to swallow. /Magnus -------------- next part -------------- An HTML attachment was scrubbed... URL: From coderanger2025 at outlook.com Sat Jan 11 22:06:26 2025 From: coderanger2025 at outlook.com (Code Ranger) Date: Sun, 12 Jan 2025 00:06:26 +0200 Subject: How to open a package from a module in the boot layer to a module in another layer? Message-ID: I have an application that consists of a main part and plugins. The main part is in the boot layer, and for each plugin, a child layer is created. Plugins are dynamically added and removed. In one of my plugins, I use Gson, which requires the API module (located in the boot layer) to open a package to Gson. The boot layer controller is not accessible. Important! A few days ago (2025-01-08), I created an issue with ID 9077987 suggesting providing access to the boot layer controller, as it is impossible to work without it. However, my issue probably hasn't been reviewed yet, as I haven't received an email with the JDK_ID. However, considering that implementing this issue may take many years, can someone suggest a workaround I should use in the meantime? I would appreciate any help. Best regards, Mike From alan.bateman at oracle.com Sun Jan 12 08:35:45 2025 From: alan.bateman at oracle.com (Alan Bateman) Date: Sun, 12 Jan 2025 08:35:45 +0000 Subject: How to open a package from a module in the boot layer to a module in another layer? In-Reply-To: References: Message-ID: On 11/01/2025 22:06, Code Ranger wrote: > I have an application that consists of a main part and plugins. The > main part is in the boot layer, and for each plugin, a child layer is > created. Plugins are dynamically added and removed. > > In one of my plugins, I use Gson, which requires the API module > (located in the boot layer) to open a package to Gson. The boot layer > controller is not accessible. > > Important! A few days ago (2025-01-08), I created an issue with ID > 9077987 suggesting providing access to the boot layer controller, as > it is impossible to work without it. However, my issue probably hasn't > been reviewed yet, as I haven't received an email with the JDK_ID. JDK-8347283 [1] was created a few days ago, looks like the same topic. From the information in this mail then it looks like the API module (in the boot layer) will need to open, using Module.addOpens, its package to the plugin that uses Gson. The plugin will then, in turn, open it to the Gson module. The API module doesn't need to know anything about Gson in this setup, but it does allow need to allow for plugins that possibly break in. -Alan [1] https://bugs.openjdk.org/browse/JDK-8347283 From coderanger2025 at outlook.com Sun Jan 12 09:12:52 2025 From: coderanger2025 at outlook.com (Code Ranger) Date: Sun, 12 Jan 2025 11:12:52 +0200 Subject: How to open a package from a module in the boot layer to a module in another layer? In-Reply-To: References: Message-ID: 1. I see that JDK-8347283 was closed? with your comment. I don't agree with you decision, but I can be wrong. Let me explain, why I think that is wrong using this concrete example. Boot layer has jdk modules and main application modules. The CORE module of the application creates plugins with child layers. No one in the world can know what plugins will be created and used when the main application starts. Now, somewhere in the future, the module A from plugin X will require module B from boot layer to open its package to module A. I believe, that the only solution to do it is to provide the controller of the boot layer. 2. Now, I tried to do apiModule.addOpens in CORE module. I got: java.lang.IllegalCallerException: com.foo.api.packagename is not open to module com.foo.core ?? ?at java.base/java.lang.Module.addOpens(Module.java:918) ~[?:?] Therefore, as far as I understand, for the solution you are suggesting to work, the packagename package of the API module must be opened to the Core module. But the main problem, as I've said above - no one knows in advance which packages of which modules from the boot layer will need to be opened/exported, etc., to the plugins that will be created by users and deployed dynamically. So, I still have no solution for this problem. This question is very important for me. If you say, that boot layer controller can't be provided, please, suggest a good solution for this problem. I think you will agree that to open/export all packages of all modules of the boot layer to CORE module is a bad solution. I really need to find a way how to do to, so I will test every your suggestion. On 1/12/25 10:35, Alan Bateman wrote: > > > On 11/01/2025 22:06, Code Ranger wrote: >> I have an application that consists of a main part and plugins. The main part is in the boot layer, and for each plugin, a child layer is created. Plugins are dynamically added and removed. >> >> In one of my plugins, I use Gson, which requires the API module (located in the boot layer) to open a package to Gson. The boot layer controller is not accessible. >> >> Important! A few days ago (2025-01-08), I created an issue with ID 9077987 suggesting providing access to the boot layer controller, as it is impossible to work without it. However, my issue probably hasn't been reviewed yet, as I haven't received an email with the JDK_ID. > > JDK-8347283 [1] was created a few days ago, looks like the same topic. > > From the information in this mail then it looks like the API module (in the boot layer) will need to open, using Module.addOpens, its package to the plugin that uses Gson. The plugin will then, in turn, open it to the Gson module. The API module doesn't need to know anything about Gson in this setup, but it does allow need to allow for plugins that possibly break in. > > -Alan > > [1] https://bugs.openjdk.org/browse/JDK-8347283 From alan.bateman at oracle.com Mon Jan 13 07:54:48 2025 From: alan.bateman at oracle.com (Alan Bateman) Date: Mon, 13 Jan 2025 07:54:48 +0000 Subject: How to open a package from a module in the boot layer to a module in another layer? In-Reply-To: References: Message-ID: On 12/01/2025 09:12, Code Ranger wrote: > 1. I see that JDK-8347283 was closed? with your comment. I don't agree > with you decision, but I can be wrong. Let me explain, why I think > that is wrong using this concrete example. > > Boot layer has jdk modules and main application modules. The CORE > module of the application creates plugins with child layers. No one in > the world can know what plugins will be created and used when the main > application starts. Now, somewhere in the future, the module A from > plugin X will require module B from boot layer to open its package to > module A. I believe, that the only solution to do it is to provide the > controller of the boot layer. > > 2. Now, I tried to do apiModule.addOpens in CORE module. I got: > > java.lang.IllegalCallerException: com.foo.api.packagename is not open > to module com.foo.core > ?? ?at java.base/java.lang.Module.addOpens(Module.java:918) ~[?:?] > > > Therefore, as far as I understand, for the solution you are suggesting > to work, the packagename package of the API module must be opened to > the Core module. But the main problem, as I've said above - no one > knows in advance which packages of which modules from the boot layer > will need to be opened/exported, etc., to the plugins that will be > created by users and deployed dynamically. Your second mail reveals a bit more but it's not clear if your issue is one of these scenarios: 1. A serialization library that is incompatible with strong encapsulation. If so, that's a different discussion. 2. The API and CORE modules have some interesting internals that the authors of these modules have chosen not to export. The author of a plugin doesn't agree. As you've found, this can only be facilitated with cooperation from code in CORE. It may additionally require CLI option if API won't open its packages to CORE. This means running with --add-opens API/com.foo.api=CORE so that CORE can open API's package to the plugin module in the child layer. 3. A badly behaved plugin that depends on the internals of standard or JDK modules. This would be whack-a-mole and require a combination of CLI options and code in CORE to open java.* and jdk.* packages to the offending code in the plugin. -Alan From coderanger2025 at outlook.com Mon Jan 13 09:46:03 2025 From: coderanger2025 at outlook.com (Code Ranger) Date: Mon, 13 Jan 2025 11:46:03 +0200 Subject: How to open a package from a module in the boot layer to a module in another layer? In-Reply-To: References: Message-ID: Hello, Alan Thank you for your suggestions, help, and time. I truly appreciate and am deeply grateful for them. However, I?m afraid I failed to convey the most crucial point. Therefore, I decided to illustrate it graphically. I believe everything will become clear now. Please, see https://ibb.co/bLTzp0n If you have any questions, I?m ready to answer them, as I?ve already mentioned, this matter is extremely important to me. On 1/13/25 09:54, Alan Bateman wrote: > On 12/01/2025 09:12, Code Ranger wrote: >> 1. I see that JDK-8347283 was closed? with your comment. I don't agree with you decision, but I can be wrong. Let me explain, why I think that is wrong using this concrete example. >> >> Boot layer has jdk modules and main application modules. The CORE module of the application creates plugins with child layers. No one in the world can know what plugins will be created and used when the main application starts. Now, somewhere in the future, the module A from plugin X will require module B from boot layer to open its package to module A. I believe, that the only solution to do it is to provide the controller of the boot layer. >> >> 2. Now, I tried to do apiModule.addOpens in CORE module. I got: >> >> java.lang.IllegalCallerException: com.foo.api.packagename is not open to module com.foo.core >> ?? ?at java.base/java.lang.Module.addOpens(Module.java:918) ~[?:?] >> >> >> Therefore, as far as I understand, for the solution you are suggesting to work, the packagename package of the API module must be opened to the Core module. But the main problem, as I've said above - no one knows in advance which packages of which modules from the boot layer will need to be opened/exported, etc., to the plugins that will be created by users and deployed dynamically. > > Your second mail reveals a bit more but it's not clear if your issue is one of these scenarios: > > 1. A serialization library that is incompatible with strong encapsulation. If so, that's a different discussion. > > 2. The API and CORE modules have some interesting internals that the authors of these modules have chosen not to export. The author of a plugin doesn't agree. As you've found, this can only be facilitated with cooperation from code in CORE. It may additionally require CLI option if API won't open its packages to CORE. This means running with --add-opens API/com.foo.api=CORE so that CORE can open API's package to the plugin module in the child layer. > > 3. A badly behaved plugin that depends on the internals of standard or JDK modules. This would be whack-a-mole and require a combination of CLI options and code in CORE to open java.* and jdk.* packages to the offending code in the plugin. > > -Alan > > From david.lloyd at redhat.com Mon Jan 13 15:25:47 2025 From: david.lloyd at redhat.com (David Lloyd) Date: Mon, 13 Jan 2025 09:25:47 -0600 Subject: `requires static` versus service binding In-Reply-To: References: <34f95d77-c081-4d26-b61c-adab76e151c0@oracle.com> Message-ID: On Fri, Jan 10, 2025 at 11:22?AM Magnus Ihse Bursie < magnus.ihse.bursie at oracle.com> wrote: > On 2025-01-08 22:33, David Lloyd wrote: > > Thus I'm inclined to believe that this restriction does not serve any > practical benefit, and I hope it can be reconsidered to be respecified as > a compile-time-only check. > > I agree. I was bitten by this as a Java developer in a hobby open source > project, and even if at some point I understood why things where the way > they are, I do not remember the reasoning, and I still find it confusing > that it did not work as I expected it to, nor what steps I were supposed to > take instead to resolve the problem at hand. > > I understand that this is not a very common problem or a high-priority > issue, and I would have accepted that it was down-prioritized to the point > that it will take a long time to resolve, but the current "works as > intended" approach is still a bit hard for me to swallow. > I think there's a bit of self-selection: this kind of problem mostly appears in more complex systems; the work to move complex systems to JPMS is already nonzero; complex systems do not move because of this kind of problem; therefore, the problem is considered a non-issue because nobody is complaining about it. As an experimental workaround I was trimming optional dependencies from the descriptor at run time and doing a late `addReads` instead if the dependency is present. This part works fine, however I then also have to strip out `uses` and sometimes `provides` for this to work if they correspond to packages in the optional dependency (which is a check that also incurs a run time cost), and adding those back to the module late requires hacky workarounds: for `addUses` I have to generate a class into the target module so that it can call `Module.addUses` on my behalf, and for `addProvides`, I have to access private JDK internals thus requiring `--add-exports` of a core JDK package, which is less than ideal. I did propose a patch to allow controllers to add these but it was soundly rejected and the ensuing discussion yielded little of value. So hopefully we can get around it another way: by allowing `uses` and `provides` of services whose packages are not present at run time. -- - DML ? he/him -------------- next part -------------- An HTML attachment was scrubbed... URL: From christian.beikov at gmail.com Mon Jan 13 16:49:11 2025 From: christian.beikov at gmail.com (Christian Beikov) Date: Mon, 13 Jan 2025 17:49:11 +0100 Subject: `requires static` versus service binding In-Reply-To: References: <34f95d77-c081-4d26-b61c-adab76e151c0@oracle.com> Message-ID: <1796f0a7-15e1-45f9-9494-ed7a0caf5638@gmail.com> Hi, just wanted to say that I have also run into this issue recently when introducing module-infos in Blaze-Persistence. Having to use `requires` instead of `requires static` when also wanting to provide a service is really unfortunate. Either I have to split the module and make the setup harder for users or impose potentially unnecessary dependencies onto a user application. Regards, Christian Am 13.01.2025 um 16:25 schrieb David Lloyd: > > > On Fri, Jan 10, 2025 at 11:22?AM Magnus Ihse Bursie > wrote: > > On 2025-01-08 22:33, David Lloyd wrote: > >> Thus I'm inclined to believe that this restriction does not serve >> any practical benefit, and I hope it can be reconsideredto be >> respecified as a compile-time-only?check. > > I agree. I was bitten by this as a Java developer in a hobby open > source project, and even if at some point I understood why things > where the way they are, I do not remember the reasoning, and I > still find it confusing that it did not work as I expected it to, > nor what steps I were supposed to take instead to resolve the > problem at hand. > > I understand that this is not a very common problem or a > high-priority issue, and I would have accepted that it was > down-prioritized to the point that it will take a long time to > resolve, but the current "works as intended" approach is still a > bit hard for me to swallow. > > I think there's a bit of self-selection: this kind of problem mostly > appears in more complex systems; the work to move complex systems to > JPMS is already nonzero; complex systems do not move because of this > kind of problem; therefore, the problem is considered a non-issue > because nobody is complaining about it. > > As an experimental workaround I was trimming optional dependencies > from the descriptor at run time and doing a late `addReads` instead if > the dependency is present. This part works fine, however I then also > have to strip out `uses` and sometimes `provides` for this to work if > they correspond to packages in the optional dependency (which is a > check that also incurs a run time cost), and adding those back to the > module late requires hacky workarounds: for `addUses` I have to > generate a class into the target module so that it can call > `Module.addUses` on my behalf, and for `addProvides`, I have to access > private JDK internals thus requiring `--add-exports` of a core JDK > package, which is less than ideal. I did propose a patch to allow > controllers to add these but it was soundly rejected and the ensuing > discussion yielded little of value. So hopefully we can get around it > another way: by allowing `uses` and `provides` of services whose > packages are not present at run time. > > -- > - DML ? he/him -------------- next part -------------- An HTML attachment was scrubbed... URL: From alan.bateman at oracle.com Mon Jan 13 17:37:15 2025 From: alan.bateman at oracle.com (Alan Bateman) Date: Mon, 13 Jan 2025 17:37:15 +0000 Subject: `requires static` versus service binding In-Reply-To: References: <34f95d77-c081-4d26-b61c-adab76e151c0@oracle.com> Message-ID: <55e20d98-bb8f-41a5-bc41-6735bdae4e5a@oracle.com> On 10/01/2025 17:21, Magnus Ihse Bursie wrote: > : > > I understand that this is not a very common problem or a high-priority > issue, and I would have accepted that it was down-prioritized to the > point that it will take a long time to resolve, but the current "works > as intended" approach is still a bit hard for me to swallow. > > `requires static` was added to support annotations that aren't needed at runtime, and also some configuration cases. I don't think support for optional service interfaces has been ruled out but it's more complex to specify that it might appear. -Alan From alex.buckley at oracle.com Mon Jan 13 20:51:43 2025 From: alex.buckley at oracle.com (Alex Buckley) Date: Mon, 13 Jan 2025 12:51:43 -0800 Subject: How to open a package from a module in the boot layer to a module in another layer? In-Reply-To: References: Message-ID: <97a53f4d-2e15-4c2c-a21e-7fb0468f4195@oracle.com> Mike/Code Ranger, the obvious suggestion is to put your application (including the "CORE module") in its own layer, rather than the boot layer. Alex On 1/13/2025 1:46 AM, Code Ranger wrote: > Hello, Alan > > Thank you for your suggestions, help, and time. I truly appreciate and > am deeply grateful for them. > > However, I?m afraid I failed to convey the most crucial point. > Therefore, I decided to illustrate it graphically. I believe everything > will become clear now. > > Please, see https://ibb.co/bLTzp0n > > If you have any questions, I?m ready to answer them, as I?ve already > mentioned, this matter is extremely important to me. > > > On 1/13/25 09:54, Alan Bateman wrote: >> On 12/01/2025 09:12, Code Ranger wrote: >>> 1. I see that JDK-8347283 was closed? with your comment. I don't >>> agree with you decision, but I can be wrong. Let me explain, why I >>> think that is wrong using this concrete example. >>> >>> Boot layer has jdk modules and main application modules. The CORE >>> module of the application creates plugins with child layers. No one >>> in the world can know what plugins will be created and used when the >>> main application starts. Now, somewhere in the future, the module A >>> from plugin X will require module B from boot layer to open its >>> package to module A. I believe, that the only solution to do it is to >>> provide the controller of the boot layer. >>> >>> 2. Now, I tried to do apiModule.addOpens in CORE module. I got: >>> >>> java.lang.IllegalCallerException: com.foo.api.packagename is not open >>> to module com.foo.core >>> ?? ?at java.base/java.lang.Module.addOpens(Module.java:918) ~[?:?] >>> >>> >>> Therefore, as far as I understand, for the solution you are >>> suggesting to work, the packagename package of the API module must be >>> opened to the Core module. But the main problem, as I've said above - >>> no one knows in advance which packages of which modules from the boot >>> layer will need to be opened/exported, etc., to the plugins that will >>> be created by users and deployed dynamically. >> >> Your second mail reveals a bit more but it's not clear if your issue >> is one of these scenarios: >> >> 1. A serialization library that is incompatible with strong >> encapsulation. If so, that's a different discussion. >> >> 2. The API and CORE modules have some interesting internals that the >> authors of these modules have chosen not to export. The author of a >> plugin doesn't agree. As you've found, this can only be facilitated >> with cooperation from code in CORE. It may additionally require CLI >> option if API won't open its packages to CORE. This means running with >> --add-opens API/com.foo.api=CORE so that CORE can open API's package >> to the plugin module in the child layer. >> >> 3. A badly behaved plugin that depends on the internals of standard or >> JDK modules. This would be whack-a-mole and require a combination of >> CLI options and code in CORE to open java.* and jdk.* packages to the >> offending code in the plugin. >> >> -Alan >> >> > From alex.buckley at oracle.com Mon Jan 13 22:27:31 2025 From: alex.buckley at oracle.com (Alex Buckley) Date: Mon, 13 Jan 2025 14:27:31 -0800 Subject: [External] : Re: How to open a package from a module in the boot layer to a module in another layer? In-Reply-To: References: <97a53f4d-2e15-4c2c-a21e-7fb0468f4195@oracle.com> Message-ID: <87b70d59-8b43-4cc7-b22e-b47780b6873b@oracle.com> You can split your application so that a small loader module goes in the boot layer, while the bulk of the application (CORE module, API module, etc) lives in a child layer. That child layer becomes the parent for the plugins' layers. You are already resolving plugin modules (and their dependencies, such as Gson) in the context of their own layers, so no change there. Exposing the boot layer's controller would allow arbitrary code to export JDK packages without the use of --add-exports on the command line. That's a non-starter, as discussed in "Integrity by Default" (https://openjdk.org/jeps/8305968#Restrictions-on-standard-unsafe-APIs). Alex On 1/13/2025 12:58 PM, Code Ranger wrote: > Alex, thank you for your suggestion. > > Putting application in its own layer > 1) is technically impossible, because the "CORE module" creates child > layers, including the child layer you are talking about, > 2) gives nothing, because it doesn't solve the main problem when child > layer require adding directives to boot layer modules. > > Best regards, CR > > On 1/13/25 22:51, Alex Buckley wrote: >> Mike/Code Ranger, the obvious suggestion is to put your application >> (including the "CORE module") in its own layer, rather than the boot >> layer. >> >> Alex >> >> On 1/13/2025 1:46 AM, Code Ranger wrote: >>> Hello, Alan >>> >>> Thank you for your suggestions, help, and time. I truly appreciate >>> and am deeply grateful for them. >>> >>> However, I?m afraid I failed to convey the most crucial point. >>> Therefore, I decided to illustrate it graphically. I believe >>> everything will become clear now. >>> >>> Please, see https://urldefense.com/v3/__https://ibb.co/bLTzp0n__;!! >>> ACWV5N9M2RV99hQ! >>> LnYA2Im1AFI5I96HdRK8cKttxczpYE2hMPXX9jrASNBXjyB7Um4AQQe5nSLytW1VWQYs7Wx_p4gvO2F6QrwcLVh6G0MYwg$ >>> If you have any questions, I?m ready to answer them, as I?ve already >>> mentioned, this matter is extremely important to me. >>> >>> >>> On 1/13/25 09:54, Alan Bateman wrote: >>>> On 12/01/2025 09:12, Code Ranger wrote: >>>>> 1. I see that JDK-8347283 was closed with your comment. I don't >>>>> agree with you decision, but I can be wrong. Let me explain, why I >>>>> think that is wrong using this concrete example. >>>>> >>>>> Boot layer has jdk modules and main application modules. The CORE >>>>> module of the application creates plugins with child layers. No one >>>>> in the world can know what plugins will be created and used when >>>>> the main application starts. Now, somewhere in the future, the >>>>> module A from plugin X will require module B from boot layer to >>>>> open its package to module A. I believe, that the only solution to >>>>> do it is to provide the controller of the boot layer. >>>>> >>>>> 2. Now, I tried to do apiModule.addOpens in CORE module. I got: >>>>> >>>>> java.lang.IllegalCallerException: com.foo.api.packagename is not >>>>> open to module com.foo.core >>>>> ?? ?at java.base/java.lang.Module.addOpens(Module.java:918) ~[?:?] >>>>> >>>>> >>>>> Therefore, as far as I understand, for the solution you are >>>>> suggesting to work, the packagename package of the API module must >>>>> be opened to the Core module. But the main problem, as I've said >>>>> above - no one knows in advance which packages of which modules >>>>> from the boot layer will need to be opened/exported, etc., to the >>>>> plugins that will be created by users and deployed dynamically. >>>> >>>> Your second mail reveals a bit more but it's not clear if your issue >>>> is one of these scenarios: >>>> >>>> 1. A serialization library that is incompatible with strong >>>> encapsulation. If so, that's a different discussion. >>>> >>>> 2. The API and CORE modules have some interesting internals that the >>>> authors of these modules have chosen not to export. The author of a >>>> plugin doesn't agree. As you've found, this can only be facilitated >>>> with cooperation from code in CORE. It may additionally require CLI >>>> option if API won't open its packages to CORE. This means running >>>> with --add-opens API/com.foo.api=CORE so that CORE can open API's >>>> package to the plugin module in the child layer. >>>> >>>> 3. A badly behaved plugin that depends on the internals of standard >>>> or JDK modules. This would be whack-a-mole and require a combination >>>> of CLI options and code in CORE to open java.* and jdk.* packages to >>>> the offending code in the plugin. >>>> >>>> -Alan >>>> >>>> >>> >> > From coderanger2025 at outlook.com Tue Jan 14 09:17:48 2025 From: coderanger2025 at outlook.com (Code Ranger) Date: Tue, 14 Jan 2025 11:17:48 +0200 Subject: [External] : Re: How to open a package from a module in the boot layer to a module in another layer? In-Reply-To: <87b70d59-8b43-4cc7-b22e-b47780b6873b@oracle.com> References: <97a53f4d-2e15-4c2c-a21e-7fb0468f4195@oracle.com> <87b70d59-8b43-4cc7-b22e-b47780b6873b@oracle.com> Message-ID: Alex, thank you very much for your suggestion and the link with important information. On 1/14/25 00:27, Alex Buckley wrote: > You can split your application so that a small loader module goes in the boot layer, while the bulk of the application (CORE module, API module, etc) lives in a child layer. That child layer becomes the parent for the plugins' layers. You are already resolving plugin modules (and their dependencies, such as Gson) in the context of their own layers, so no change there. > Such a solution will lead to significant and unjustified complication of the application. At the same time, it will still not be universal, as it does not apply to JDK modules, which can only reside in the boot layer. A solution that is not universal cannot be considered a good solution. > Exposing the boot layer's controller would allow arbitrary code to export JDK packages without the use of --add-exports on the command line. That's a non-starter, as discussed in "Integrity by Default" (https://openjdk.org/jeps/8305968#Restrictions-on-standard-unsafe-APIs). > I opened this issue https://bugs.openjdk.org/browse/JDK-8347283. In this issue I suggest to open the boot layer controller ONLY to ONE module that is specified by JKD parameter. For example, it can be boot-controller-accessible-module. So, only this module will be able to use the boot layer controller. From the link you provided: > We cannot treat the mere inclusion of an unsafe-using library or framework in an application as consent by the application's developer to violate integrity. The developer might not be aware that the component uses an unsafe API. The developer might not even be aware that the component is present, since the component could be an indirect dependency several layers removed from the application itself. *The application developer must therefore explicitly configure the Java runtime to allow selected components to use unsafe APIs.* Please, pay attention to the last sentence. What I propose in the issue (JDK-8347283) fully complies with these conditions. To be honest, I don?t understand what the problem is. I am trying to provide the ability to dynamically add directives to boot-layer modules with the full consent of the application developer, without any restrictions like the mandatory prior use of --add-* parameters (which obviously defeats the whole idea of a dynamic approach). The ModuleLayer.Controller class has only four methods (essentially 1 + 1 + 1 + 1). I refuse to believe that JDK developers, who are clearly highly skilled and experienced programmers, cannot solve this problem. So, what?s the issue? Do we really want the instructions for adding a plugin in Java to look like this: 1. Install the plugin. 2. Stop the application. 3. Add --add-exports ..., --add-opens .... 4. Restart the application. Best regards, CR > Alex > > On 1/13/2025 12:58 PM, Code Ranger wrote: >> Alex, thank you for your suggestion. >> >> Putting application in its own layer >> 1) is technically impossible, because the "CORE module" creates child layers, including the child layer you are talking about, >> 2) gives nothing, because it doesn't solve the main problem when child layer require adding directives to boot layer modules. >> >> Best regards, CR >> >> On 1/13/25 22:51, Alex Buckley wrote: >>> Mike/Code Ranger, the obvious suggestion is to put your application (including the "CORE module") in its own layer, rather than the boot layer. >>> >>> Alex >>> >>> On 1/13/2025 1:46 AM, Code Ranger wrote: >>>> Hello, Alan >>>> >>>> Thank you for your suggestions, help, and time. I truly appreciate and am deeply grateful for them. >>>> >>>> However, I?m afraid I failed to convey the most crucial point. Therefore, I decided to illustrate it graphically. I believe everything will become clear now. >>>> >>>> Please, see https://urldefense.com/v3/__https://ibb.co/bLTzp0n__;!! ACWV5N9M2RV99hQ! LnYA2Im1AFI5I96HdRK8cKttxczpYE2hMPXX9jrASNBXjyB7Um4AQQe5nSLytW1VWQYs7Wx_p4gvO2F6QrwcLVh6G0MYwg$ >>>> If you have any questions, I?m ready to answer them, as I?ve already mentioned, this matter is extremely important to me. >>>> >>>> >>>> On 1/13/25 09:54, Alan Bateman wrote: >>>>> On 12/01/2025 09:12, Code Ranger wrote: >>>>>> 1. I see that JDK-8347283 was closed with your comment. I don't agree with you decision, but I can be wrong. Let me explain, why I think that is wrong using this concrete example. >>>>>> >>>>>> Boot layer has jdk modules and main application modules. The CORE module of the application creates plugins with child layers. No one in the world can know what plugins will be created and used when the main application starts. Now, somewhere in the future, the module A from plugin X will require module B from boot layer to open its package to module A. I believe, that the only solution to do it is to provide the controller of the boot layer. >>>>>> >>>>>> 2. Now, I tried to do apiModule.addOpens in CORE module. I got: >>>>>> >>>>>> java.lang.IllegalCallerException: com.foo.api.packagename is not open to module com.foo.core >>>>>> ?? ?at java.base/java.lang.Module.addOpens(Module.java:918) ~[?:?] >>>>>> >>>>>> >>>>>> Therefore, as far as I understand, for the solution you are suggesting to work, the packagename package of the API module must be opened to the Core module. But the main problem, as I've said above - no one knows in advance which packages of which modules from the boot layer will need to be opened/exported, etc., to the plugins that will be created by users and deployed dynamically. >>>>> >>>>> Your second mail reveals a bit more but it's not clear if your issue is one of these scenarios: >>>>> >>>>> 1. A serialization library that is incompatible with strong encapsulation. If so, that's a different discussion. >>>>> >>>>> 2. The API and CORE modules have some interesting internals that the authors of these modules have chosen not to export. The author of a plugin doesn't agree. As you've found, this can only be facilitated with cooperation from code in CORE. It may additionally require CLI option if API won't open its packages to CORE. This means running with --add-opens API/com.foo.api=CORE so that CORE can open API's package to the plugin module in the child layer. >>>>> >>>>> 3. A badly behaved plugin that depends on the internals of standard or JDK modules. This would be whack-a-mole and require a combination of CLI options and code in CORE to open java.* and jdk.* packages to the offending code in the plugin. >>>>> >>>>> -Alan >>>>> >>>>> >>>> >>> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ron.pressler at oracle.com Tue Jan 14 12:30:39 2025 From: ron.pressler at oracle.com (Ron Pressler) Date: Tue, 14 Jan 2025 12:30:39 +0000 Subject: [External] : Re: How to open a package from a module in the boot layer to a module in another layer? In-Reply-To: References: <97a53f4d-2e15-4c2c-a21e-7fb0468f4195@oracle.com> <87b70d59-8b43-4cc7-b22e-b47780b6873b@oracle.com> Message-ID: > On 14 Jan 2025, at 09:17, Code Ranger wrote: > > > To be honest, I don?t understand what the problem is. I am trying to provide the ability to dynamically add directives to boot-layer modules with the full consent of the application developer, without any restrictions like the mandatory prior use of --add-* parameters (which obviously defeats the whole idea of a dynamic approach). The ModuleLayer.Controller class has only four methods (essentially 1 + 1 + 1 + 1). I refuse to believe that JDK developers, who are clearly highly skilled and experienced programmers, cannot solve this problem. > > So, what?s the issue? Do we really want the instructions for adding a plugin in Java to look like this: > > 1. Install the plugin. > 2. Stop the application. > 3. Add --add-exports ..., --add-opens .... > 4. Restart the application. > > Best regards, CR What you?re proposing, i.e. a mechanism to grant a specific module the permission to edit the boot layer and, in particular java.base, may be workable in practice, but the problem is that it is probably a very bad idea. Opening java.base is not only unrecommended but an extreme operation that could be dangerous (even result in undefined behaviour or worse) and is meant as a temporary measure until the underlying issues that require it are fixed. Needing to open or export packages in java.base signifies a problem with the program and is not a normal or healthy mode of operation. The Integrity by Default JEP (https://openjdk.org/jeps/8305968) offers recommendations for how code that, say, serializes java.base classes should work without opening java.base. Remember that modules are a feature added to allow code that needs to trust certain invariants to do so, and the JDK modules, java.base in particular, need such invariants to ensure their correct operation. A plugin that requires hacking the JDK internals is a problematic plugin, and one that could risk the entire application. The user needs to be aware when such a plugin is used. If you believe it's okay for the invariants of your core components possibly being compromised by plugins, that?s fine ? and you can do what Alex suggested ? but the JDK isn?t okay with that. If you insist on opening java.base to all code, that is an extreme, non-standard, and dangerous mode that *should* require extreme measures such as employing an agent ? not a standard API. ? Ron From adinn at redhat.com Tue Jan 14 13:06:36 2025 From: adinn at redhat.com (Andrew Dinn) Date: Tue, 14 Jan 2025 13:06:36 +0000 Subject: [External] : Re: How to open a package from a module in the boot layer to a module in another layer? In-Reply-To: References: <97a53f4d-2e15-4c2c-a21e-7fb0468f4195@oracle.com> <87b70d59-8b43-4cc7-b22e-b47780b6873b@oracle.com> Message-ID: Hi Ron, On 14/01/2025 12:30, Ron Pressler wrote: > If you believe it's okay for the invariants of your core components possibly being compromised by plugins, that?s fine ? and you can do what Alex suggested ? but the JDK isn?t okay with that. If you insist on opening java.base to all code, that is an extreme, non-standard, and dangerous mode that *should* require extreme measures such as employing an agent ? not a standard API. I am afraid that last sentence doesn't make much sense to me. I certainly think Java devs should and mostly do agree that opening java.base to all code is a non-standard and risky mode in which to operate the JVM (n.b. I switched out 'dangerous' and 'extreme' as I'm not quite sure what they add to your pejorative assessment beyond jeremiad-redolent rhetoric). However, you also seem to be saying that employing an agent is an extreme measure. How so? I have a corollary question: are you implying that using an agent to expose java.base code selectively to targeted library, framework or, even, application code is always inherently risky (dangerous or extreme, even)? I ask because agents *are* provided with a API that explicitly enables them to do this and you appear to be suggesting that this was/is a mistake (n.b. that API was added because I demonstrated that, absent such an API and given sufficient bytecode weaving ingenuity, an agent can easily achieve the same outcome as if it were to use the API, only probably with more risk of error). regards, Andrew Dinn ----------- Red Hat Distinguished Engineer Red Hat UK Ltd Registered in England and Wales under Company Registration No. 03798903 Directors: Michael Cunningham, Michael ("Mike") O'Neill From coderanger2025 at outlook.com Tue Jan 14 13:26:49 2025 From: coderanger2025 at outlook.com (Code Ranger) Date: Tue, 14 Jan 2025 15:26:49 +0200 Subject: [External] : Re: How to open a package from a module in the boot layer to a module in another layer? In-Reply-To: References: <97a53f4d-2e15-4c2c-a21e-7fb0468f4195@oracle.com> <87b70d59-8b43-4cc7-b22e-b47780b6873b@oracle.com> Message-ID: On 1/14/25 14:30, Ron Pressler wrote: > What you?re proposing, i.e. a mechanism to grant a specific module the permission to edit the boot layer and, in particular java.base, may be workable in practice, but the problem is that it is probably a very bad idea. > > Opening java.base is not only unrecommended but an extreme operation that could be dangerous (even result in undefined behaviour or worse) and is meant as a temporary measure until the underlying issues that require it are fixed. Needing to open or export packages in java.base signifies a problem with the program and is not a normal or healthy mode of operation. The Integrity by Default JEP (https://openjdk.org/jeps/8305968) offers recommendations for how code that, say, serializes java.base classes should work without opening java.base. > > Remember that modules are a feature added to allow code that needs to trust certain invariants to do so, and the JDK modules, java.base in particular, need such invariants to ensure their correct operation. A plugin that requires hacking the JDK internals is a problematic plugin, and one that could risk the entire application. The user needs to be aware when such a plugin is used. > > If you believe it's okay for the invariants of your core components possibly being compromised by plugins, that?s fine ? and you can do what Alex suggested ? but the JDK isn?t okay with that. If you insist on opening java.base to all code, that is an extreme, non-standard, and dangerous mode that *should* require extreme measures such as employing an agent ? not a standard API. > > ? Ron > You are shifting the focus of my issue. My issue is not about opening modules in the boot layer but about doing dynamically what can currently only be done statically using the --add-* parameters. I agree with you that adding custom directives to JDK modules is a bad idea? a very bad idea? a temporary solution? something to be avoided. Yes, I completely agree with you. But I?m talking about something else. I?m saying that since we are sometimes forced to add these directives, let?s make it possible not only during JVM startup but also at runtime. In other words, you?re saying: --add-opens java.base/java.time=json???? //this is bad, but the JDK supports it because it?s unavoidable. bootLayerController.addOpen(baseModule, "java.time", jsonModule) //this is bad, the JDK will not support it because it?s bad, very bad, unacceptably bad. But I?m saying that these two solutions are equivalent?at least they should be (I haven?t tested it). However, the second solution is more flexible, convenient, and even safer. Yes, it is safer. Please, see this SO answer that is the most upvoted - https://stackoverflow.com/a/70878195 As for the temporary nature of this solution?that?s not a problem. Access to the boot layer controller can be removed at the same time as the --add-* parameters. I think by the year 3080, this feature will no longer be relevant. -------------- next part -------------- An HTML attachment was scrubbed... URL: From ron.pressler at oracle.com Tue Jan 14 13:28:54 2025 From: ron.pressler at oracle.com (Ron Pressler) Date: Tue, 14 Jan 2025 13:28:54 +0000 Subject: [External] : Re: How to open a package from a module in the boot layer to a module in another layer? In-Reply-To: References: <97a53f4d-2e15-4c2c-a21e-7fb0468f4195@oracle.com> <87b70d59-8b43-4cc7-b22e-b47780b6873b@oracle.com> Message-ID: > On 14 Jan 2025, at 13:06, Andrew Dinn wrote: > > > I certainly think Java devs should and mostly do agree that opening java.base to all code is a non-standard and risky mode in which to operate the JVM (n.b. I switched out 'dangerous' and 'extreme' as I'm not quite sure what they add to your pejorative assessment beyond jeremiad-redolent rhetoric). However, you also seem to be saying that employing an agent is an extreme measure. How so? I meant extreme in its power. Seeing an agent declared on the command line is good indication that ?normal rules may not apply?. Using an agent is, of course, a valid thing to do in general. > > I have a corollary question: are you implying that using an agent to expose java.base code selectively to targeted library, framework or, even, application code is always inherently risky (dangerous or extreme, even)? Opening java.base in any way is always inherently risky. It means that whether *any* platform invariants hold is now in the hands of some non-JDK code. For example, it means that no string in the program can be trusted to be immutable, and some day it may mean that non-JDK code would decide whether any array?s bounds-checking is performed . > I ask because agents *are* provided with a API that explicitly enables them to do this and you appear to be suggesting that this was/is a mistake (n.b. that API was added because I demonstrated that, absent such an API and given sufficient bytecode weaving ingenuity, an agent can easily achieve the same outcome as if it were to use the API, only probably with more risk of error). I don?t think it?s a mistake because sometimes it is useful to change the laws of the universe. The use of an agent signifies that the laws of the universe are now in the hands of the agent rather than the JDK, and as long as that?s clear, I think it?s fine. The idea of integrity by default is that the *application* (though not libraries placed on the module/class path) gets to decide what the rules are, because that?s always the case. The application controls the launcher and runtime anyway; it?s free to select a modified runtime, or even one that isn?t Java at all. Because only the application can load an agent (at least without a warning) it?s fine. What Code Ranger suggested ? adding yet *another* mechanism that hands the keys to the kingdom to some code is, I think, a bad idea because we already have agents, and their potential impact is already known. ? Ron From ron.pressler at oracle.com Tue Jan 14 13:42:29 2025 From: ron.pressler at oracle.com (Ron Pressler) Date: Tue, 14 Jan 2025 13:42:29 +0000 Subject: [External] : Re: How to open a package from a module in the boot layer to a module in another layer? In-Reply-To: References: <97a53f4d-2e15-4c2c-a21e-7fb0468f4195@oracle.com> <87b70d59-8b43-4cc7-b22e-b47780b6873b@oracle.com> Message-ID: <58357707-AE38-4CFE-AEB0-D89F02D34A9B@oracle.com> > On 14 Jan 2025, at 13:26, Code Ranger wrote: > > > On 1/14/25 14:30, Ron Pressler wrote: >> >> What you?re proposing, i.e. a mechanism to grant a specific module the permission to edit the boot layer and, in particular java.base, may be workable in practice, but the problem is that it is probably a very bad idea. >> >> Opening java.base is not only unrecommended but an extreme operation that could be dangerous (even result in undefined behaviour or worse) and is meant as a temporary measure until the underlying issues that require it are fixed. Needing to open or export packages in java.base signifies a problem with the program and is not a normal or healthy mode of operation. The Integrity by Default JEP (https://openjdk.org/jeps/8305968) offers recommendations for how code that, say, serializes java.base classes should work without opening java.base. >> >> Remember that modules are a feature added to allow code that needs to trust certain invariants to do so, and the JDK modules, java.base in particular, need such invariants to ensure their correct operation. A plugin that requires hacking the JDK internals is a problematic plugin, and one that could risk the entire application. The user needs to be aware when such a plugin is used. >> >> If you believe it's okay for the invariants of your core components possibly being compromised by plugins, that?s fine ? and you can do what Alex suggested ? but the JDK isn?t okay with that. If you insist on opening java.base to all code, that is an extreme, non-standard, and dangerous mode that *should* require extreme measures such as employing an agent ? not a standard API. >> >> ? Ron >> >> > > You are shifting the focus of my issue. My issue is not about opening modules in the boot layer but about doing dynamically what can currently only be done statically using the --add-* parameters. > > I agree with you that adding custom directives to JDK modules is a bad idea? a very bad idea? a temporary solution? something to be avoided. Yes, I completely agree with you. But I?m talking about something else. I?m saying that since we are sometimes forced to add these directives, let?s make it possible not only during JVM startup but also at runtime. In other words, you?re saying: > > --add-opens java.base/java.time=json //this is bad, but the JDK supports it because it?s unavoidable. > bootLayerController.addOpen(baseModule, "java.time", jsonModule) //this is bad, the JDK will not support it because it?s bad, very bad, unacceptably bad. > > But I?m saying that these two solutions are equivalent?at least they should be (I haven?t tested it). However, the second solution is more flexible, convenient, and even safer. Yes, it is safer. Please, see this SO answer that is the most upvoted - https://stackoverflow.com/a/70878195 > > As for the temporary nature of this solution?that?s not a problem. Access to the boot layer controller can be removed at the same time as the --add-* parameters. I think by the year 3080, this feature will no longer be relevant. What I?m saying is that since you agree that granting some component the power to decide, at runtime, that strings are not immutable and that the number 5 may sometimes have the value of 6 (as that?s what opening java.base means) will still require some static configuration, then globally changing the semantics of Java code at runtime is already possible in this way via agents (https://docs.oracle.com/en/java/javase/23/docs/api/java.instrument/java/lang/instrument/Instrumentation.html#redefineModule(java.lang.Module,java.util.Set,java.util.Map,java.util.Map,java.util.Set,java.util.Map)). The JDK already supports this and so there?s no need for yet another mechanism. ? Ron From adinn at redhat.com Tue Jan 14 13:45:28 2025 From: adinn at redhat.com (Andrew Dinn) Date: Tue, 14 Jan 2025 13:45:28 +0000 Subject: [External] : Re: How to open a package from a module in the boot layer to a module in another layer? In-Reply-To: References: <97a53f4d-2e15-4c2c-a21e-7fb0468f4195@oracle.com> <87b70d59-8b43-4cc7-b22e-b47780b6873b@oracle.com> Message-ID: <1531c696-53c3-4b37-a617-4e99aa598427@redhat.com> On 14/01/2025 13:26, Code Ranger wrote: > In other words, you?re saying: > > --add-opens java.base/java.time=json???? //this is bad, but the JDK > supports it because it?s unavoidable. > bootLayerController.addOpen(baseModule, "java.time", jsonModule) //this > is bad, the JDK will not support it because it?s bad, very bad, > unacceptably bad. > > But I?m saying that these two solutions are equivalent?at least they > should be (I haven?t tested it). However, the second solution is more > flexible, convenient, and even safer. Yes, it is safer. Please, see this > SO answer that is the most upvoted - https://stackoverflow.com/a/70878195 The two solutions are not and cannot be equivalent in one very significant aspect. In the first case JDK and JVM knows about the opening of the module from bootstrap. In the second case they both find out about it after some amount of running. This has very significant consequences. If you only have to allow for the first case then from the get go you can optimize execution on the basis that private elements of closed modules are guaranteed to remain private. If you have to allow for the second case then you either have to avoid such optimizations or make them 'speculative' i.e. implement them with a bail-out strategy which guarantees at the point where the module is opened to trap and reset/undo any operations that is in progress based on the speculation. n.b. That's why we have a default policy of not allowing agents to be loaded dynamically (absence of an agent on the command line is not enough warning to the JDK/JVM). regards, Andrew Dinn ----------- Red Hat Distinguished Engineer Red Hat UK Ltd Registered in England and Wales under Company Registration No. 03798903 Directors: Michael Cunningham, Michael ("Mike") O'Neill From coderanger2025 at outlook.com Tue Jan 14 14:13:36 2025 From: coderanger2025 at outlook.com (Code Ranger) Date: Tue, 14 Jan 2025 16:13:36 +0200 Subject: [External] : Re: How to open a package from a module in the boot layer to a module in another layer? In-Reply-To: <58357707-AE38-4CFE-AEB0-D89F02D34A9B@oracle.com> References: <97a53f4d-2e15-4c2c-a21e-7fb0468f4195@oracle.com> <87b70d59-8b43-4cc7-b22e-b47780b6873b@oracle.com> <58357707-AE38-4CFE-AEB0-D89F02D34A9B@oracle.com> Message-ID: On 1/14/25 15:42, Ron Pressler wrote: > What I?m saying is that since you agree that granting some component the power to decide, at runtime, that strings are not immutable and that the number 5 may sometimes have the value of 6 (as that?s what opening java.base means) will still require some static configuration, then globally changing the semantics of Java code at runtime is already possible in this way via agents (https://docs.oracle.com/en/java/javase/23/docs/api/java.instrument/java/lang/instrument/Instrumentation.html#redefineModule(java.lang.Module,java.util.Set,java.util.Map,java.util.Map,java.util.Set,java.util.Map)). The JDK already supports this and so there?s no need for yet another mechanism. > > ? Ron Ron, thank you for your suggestion. I didn't know about it. I have no experience working with agents, so I just read about them. Based on what I?ve read, I?ve formed the impression that agents are not the most suitable solution in terms of performance and flexibility when interacting with the main application. It seems to me that using agents is the wrong direction. Providing access to the boot layer controller appears to be a simpler and more straightforward solution. Best regards, CR -------------- next part -------------- An HTML attachment was scrubbed... URL: From coderanger2025 at outlook.com Tue Jan 14 14:43:29 2025 From: coderanger2025 at outlook.com (Code Ranger) Date: Tue, 14 Jan 2025 16:43:29 +0200 Subject: [External] : Re: How to open a package from a module in the boot layer to a module in another layer? In-Reply-To: References: <97a53f4d-2e15-4c2c-a21e-7fb0468f4195@oracle.com> <87b70d59-8b43-4cc7-b22e-b47780b6873b@oracle.com> <58357707-AE38-4CFE-AEB0-D89F02D34A9B@oracle.com> Message-ID: I have a small request for the participants from Oracle: could you please add a link to this thread in the issue JDK-8347283? Regardless of what happens with this issue, the information from our discussion might be useful. Best regards, CR From ron.pressler at oracle.com Tue Jan 14 16:08:07 2025 From: ron.pressler at oracle.com (Ron Pressler) Date: Tue, 14 Jan 2025 16:08:07 +0000 Subject: [External] : Re: How to open a package from a module in the boot layer to a module in another layer? In-Reply-To: References: <97a53f4d-2e15-4c2c-a21e-7fb0468f4195@oracle.com> <87b70d59-8b43-4cc7-b22e-b47780b6873b@oracle.com> <58357707-AE38-4CFE-AEB0-D89F02D34A9B@oracle.com> Message-ID: > On 14 Jan 2025, at 14:13, Code Ranger wrote: > > Providing access to the boot layer controller appears to be a simpler and more straightforward solution. I can assure you it is not. ? Ron From alan.bateman at oracle.com Tue Jan 14 16:50:51 2025 From: alan.bateman at oracle.com (Alan Bateman) Date: Tue, 14 Jan 2025 16:50:51 +0000 Subject: [External] : Re: How to open a package from a module in the boot layer to a module in another layer? In-Reply-To: References: <97a53f4d-2e15-4c2c-a21e-7fb0468f4195@oracle.com> <87b70d59-8b43-4cc7-b22e-b47780b6873b@oracle.com> Message-ID: On 14/01/2025 09:17, Code Ranger wrote: > Alex, thank you very much for your suggestion and the link with > important information. > > On 1/14/25 00:27, Alex Buckley wrote: >> You can split your application so that a small loader module goes in >> the boot layer, while the bulk of the application (CORE module, API >> module, etc) lives in a child layer. That child layer becomes the >> parent for the plugins' layers. You are already resolving plugin >> modules (and their dependencies, such as Gson) in the context of >> their own layers, so no change there. >> > > Such a solution will lead to significant and unjustified complication > of the application. At the same time, it will still not be universal, > as it does not apply to JDK modules, which can only reside in the boot > layer. A solution that is not universal cannot be considered a good > solution. Alex's suggestion is good, esp. for the scenario where there is discord between the authors of API+CORE and the author of a plugin that wants to access the internals of one or both of these modules. For the JDK modules then I think we need to understand more about the issues you are dealing with. Is this about serialization, or is this plugin code that needs to be fixed to not depend on JDK internals. We get it that you can't know all the bad things that these plugins might do but this doesn't mean it's a problem that should be solved. -Alan From coderanger2025 at outlook.com Tue Jan 14 17:12:17 2025 From: coderanger2025 at outlook.com (Code Ranger) Date: Tue, 14 Jan 2025 19:12:17 +0200 Subject: [External] : Re: How to open a package from a module in the boot layer to a module in another layer? In-Reply-To: References: <97a53f4d-2e15-4c2c-a21e-7fb0468f4195@oracle.com> <87b70d59-8b43-4cc7-b22e-b47780b6873b@oracle.com> Message-ID: On 1/14/25 18:50, Alan Bateman wrote: > > For the JDK modules then I think we need to understand more about the issues you are dealing with. Is this about serialization, or is this plugin code that needs to be fixed to not depend on JDK internals. We get it that you can't know all the bad things that these plugins might do?but?this?doesn't?mean?it's?a?problem?that?should?be?solved. Why did you add --add-* parameters to JDK? Is it a problem that should be solved? We are going in circles. I have explained in great detail the limitations of the --add-* parameters. I provided a visual representation of the issue. I keep emphasizing over and over again ? the issue is not whether to add custom directives or not, but rather to add them DYNAMICALLY. I also thoroughly explained the limitations of module.addX() and why they can't solve the problem. Regarding the agent ? who is ready to add such an agent to their application to manage module directives and present it to the community? I have nothing else to add. Really, nothing. The ball is in your court. Either reopen the issue, or Java developers, to the delight of developers in C#, Python, JS, etc., will have to write such instructions for their plugins: 1. Install the plugin. 2. Stop the application. 3. Add --add-exports ..., --add-opens .... 4. Restart the application. Best regards, CR From michal at kleczek.org Tue Jan 14 17:45:08 2025 From: michal at kleczek.org (=?utf-8?Q?Micha=C5=82_K=C5=82eczek?=) Date: Tue, 14 Jan 2025 18:45:08 +0100 Subject: [External] : Re: How to open a package from a module in the boot layer to a module in another layer? Message-ID: <8A6FABC5-5165-44E2-A023-57BFAB4CA03B@kleczek.org> ? Micha? > On 14 Jan 2025, at 18:14, Code Ranger wrote: > ? > > On 1/14/25 18:50, Alan Bateman wrote: >> >> For the JDK modules then I think we need to understand more about the issues you are dealing with. Is this about serialization, or is this plugin code that needs to be fixed to not depend on JDK internals. We get it that you can't know all the bad things that these plugins might do but this doesn't mean it's a problem that should be solved. > > Why did you add --add-* parameters to JDK? Is it a problem that should be solved? > > We are going in circles. I have explained in great detail the limitations of the --add-* parameters. I am a little lost now. OpenJDK developers say it is their goal NOT to enable any third party module to easily bypass integrity protections. ?Easy? is the key word: they make it possible to do so, as your application can embed runtime configured with an agent or you can implement the solution described by Alex, but they make it difficult on purpose. And that is their goal. Yet they still ask you about the actual use case as they are open to the idea that maybe they missed something important and the goal as stated And you don?t provide any. Being myself a huge sceptic of the direction towards static linking - I fail to see what your goal is. Why do you think it should be easierfor your library to bypass built-in integrity protections? Michal From ron.pressler at oracle.com Tue Jan 14 19:28:51 2025 From: ron.pressler at oracle.com (Ron Pressler) Date: Tue, 14 Jan 2025 19:28:51 +0000 Subject: [External] : Re: How to open a package from a module in the boot layer to a module in another layer? In-Reply-To: References: <97a53f4d-2e15-4c2c-a21e-7fb0468f4195@oracle.com> <87b70d59-8b43-4cc7-b22e-b47780b6873b@oracle.com> Message-ID: > On 14 Jan 2025, at 17:12, Code Ranger wrote: > > > Regarding the agent ? who is ready to add such an agent to their application to manage module directives and present it to the community? I would think that certainly anyone who?s writing a project that lets any code, including code loaded dynamically at runtime, redefine the semantics of Java globally for the application would have no problem at all using an agent. An agent *is* how Java programs change, at runtime, various things that are otherwise static, and that is exactly what you?re asking to do. There are many big and important Java programs running in production with agents, and most of them are programs that don?t even go as far as you aim to in terms of liberties granted to dynamically loaded code. > > I have nothing else to add. Really, nothing. The ball is in your court. Either reopen the issue, or Java developers, to the delight of developers in C#, Python, JS, etc., will have to write such instructions for their plugins: > > 1. Install the plugin. > 2. Stop the application. > 3. Add --add-exports ..., --add-opens .... > 4. Restart the application. These things are not required. You can do what you want without any restarts or reconfiguration with just plain Java code *except* when dynamically loaded plugins want to manipulate the inner workings of the JDK itself, something that you?d really want to raise a red flag over. And if you?re fine with letting plugin code manipulate the runtime, you can simply add a single flag specifying an agent, which is not only how Java has always supported things of this sort but also requires the same configuration effort as in your suggestion ? a single flag. It?s not a matter of not recognising that what you want may sometimes be pragmatically needed. It?s just that everything you?re asking for is already delivered and you?re requesting a feature that already exists. ? Ron From alex.buckley at oracle.com Tue Jan 14 20:38:07 2025 From: alex.buckley at oracle.com (Alex Buckley) Date: Tue, 14 Jan 2025 12:38:07 -0800 Subject: [External] : Re: How to open a package from a module in the boot layer to a module in another layer? In-Reply-To: References: <97a53f4d-2e15-4c2c-a21e-7fb0468f4195@oracle.com> <87b70d59-8b43-4cc7-b22e-b47780b6873b@oracle.com> Message-ID: <53945ae0-70b9-4e76-b3bd-5e80d1b24b1c@oracle.com> On 1/14/2025 9:12 AM, Code Ranger wrote: > Why did you add --add-* parameters to JDK? Is it a problem that should > be solved? The "Integrity by Default" JEP explains that there are four unsafe APIs -- see https://openjdk.org/jeps/8305968#Undermining-integrity. The JEP goes on to explain that these APIs are "essential for a relatively small number of libraries, frameworks, and tools whose core functionality cannot be implemented any other way" -- see https://openjdk.org/jeps/8305968#Restrictions-on-standard-unsafe-APIs. The JEP then ties the --add-* and other command line options directly to the four unsafe APIs. The purpose of these command line options is to enumerate which specific code needs to use unsafe APIs. This provides an audit function if use of unsafe APIs leads to problems for users. The best number of these command line options is zero, which means nothing in the stack is using unsafe APIs and the stack can be expected to run smoothly on newer JDKs. You have proposed a command line option that gives superpowers to a specific module, so it can obtain and manipulate the boot layer's controller. This option will not be added, for two reasons: 1. It's not related to use of the unsafe APIs. It just happens to feel similar. Outside the domain of unsafe APIs (and setting aside "meta" topics like preview APIs), we don't offer command line options that let some code do things which are unavailable or disallowed in the Java Platform API for other code. 2. It's specific about which module would have superpowers, but there's no auditability for users. The module's code is a black box: it could export different packages to different clients at different times. I expect you view this flexibility as a feature, but we view it as a problem: there is nothing to stop the module from opening JDK internals so that other code (perhaps in a different module) can use setAccessible, an unsafe API, to access them _without any command line acknowledgement that this is occurring_. This open-ended, back-door access to JDK internals flies directly in the face of our integrity-by-default policy. The recommended solution for you is to load the bulk of your application and its plugins in their own layers, outside the boot layer. You will then have supreme control over the accessibility of your own code and any third party code that you load. Access to JDK internals -- whether unsupported classes in jdk.internal.* packages or undocumented members of the java.time package -- is something for users to grant to you, not something for you to take. Alex From coderanger2025 at outlook.com Wed Jan 15 09:02:28 2025 From: coderanger2025 at outlook.com (Code Ranger) Date: Wed, 15 Jan 2025 11:02:28 +0200 Subject: JDK-8347336 Add name property for every ModuleLayer instance Message-ID: When working with multiple ModuleLayers, it often becomes necessary to identify a specific layer and distinguish it from others. For example, when ModuleLayers are used for plugins, and the program retrieves a layer for a specific plugin, a map is typically required to determine which plugin the layer belongs to in order to give some name to the layer. However, when different libraries interact with a layer, the need for layer identification becomes even more pressing. For instance, consider receiving a LogEvent in log4j2. By default, log4j2 provides information about the module that created the event via logEvent.getSource().moduleName. However, having only the module name, without the layer name, is not very helpful. The reason for this is that a module is part of a layer, and there can be multiple layers where a module with the same name is used. Thus, if we want to obtain log events for a specific plugin, we are forced to reinvent the wheel, as LogEvent does not provide access to the layer name. This limitation arises because, at present, ModuleLayer does not have a getName() method. Because of this, I filed JDK-8347336. I would like to hear the opinions of JPMS developers and understand whether this issue will be addressed or not. For example, it is possible to overload the methods defineModulesWithManyLoaders, defineModulesWithOneLoader etc adding a String name parameter, and add the getName() method to ModuleLayer. So, the name will be specified by user, at the same time ModuleLayer will be immutable. From adinn at redhat.com Wed Jan 15 09:22:37 2025 From: adinn at redhat.com (Andrew Dinn) Date: Wed, 15 Jan 2025 09:22:37 +0000 Subject: [External] : Re: How to open a package from a module in the boot layer to a module in another layer? In-Reply-To: References: <97a53f4d-2e15-4c2c-a21e-7fb0468f4195@oracle.com> <87b70d59-8b43-4cc7-b22e-b47780b6873b@oracle.com> Message-ID: <9cb2b530-39d2-4f29-81b1-5ab923597195@redhat.com> On 14/01/2025 17:12, Code Ranger wrote: > Regarding the agent ? who is ready to add such an agent to their > application to manage module directives and present it to the community? Well, there is already one example of an agent that manages access to module private code which is widely in use by the community. On JDK9+ Byteman allows injected code to access methods that are not exported by modules, using the module open APIs provided to class Instrumentation. It does so using its own module layer and associated controller. It is also implemented to behave compatibly on JDK8 where it achieves the same outcome using reflection. Most notably, on JDK9+ Byteman avoids exposing those unexported methods to anything other than the injected code. regards, Andrew Dinn ----------- From coderanger2025 at outlook.com Wed Jan 15 09:37:31 2025 From: coderanger2025 at outlook.com (Code Ranger) Date: Wed, 15 Jan 2025 11:37:31 +0200 Subject: [External] : Re: How to open a package from a module in the boot layer to a module in another layer? In-Reply-To: <9cb2b530-39d2-4f29-81b1-5ab923597195@redhat.com> References: <97a53f4d-2e15-4c2c-a21e-7fb0468f4195@oracle.com> <87b70d59-8b43-4cc7-b22e-b47780b6873b@oracle.com> <9cb2b530-39d2-4f29-81b1-5ab923597195@redhat.com> Message-ID: On 1/15/25 11:22, Andrew Dinn wrote: > On 14/01/2025 17:12, Code Ranger wrote: >> Regarding the agent ? who is ready to add such an agent to their application to manage module directives and present it to the community? > > Well, there is already one example of an agent that manages access to module private code which is widely in use by the community. On JDK9+ Byteman allows injected code to access methods that are not exported by modules, using the module open APIs provided to class Instrumentation. It does so using its own module layer and associated controller. It is also implemented to behave compatibly on JDK8 where it achieves the same outcome using reflection. Most notably, on JDK9+ Byteman avoids exposing those unexported methods to anything other than the injected code. > Andrew, thank you for you this example. From https://github.com/bytemanproject/byteman (if this is the project you are talking about): Byteman supports injection of side effects into Java programs for the purpose of *tracing *and *testing* application behaviour. No, I am sure, using agents to add open/export to a module from the boot layer can hardly be called an optimal and elegant solution. Therefore, I decided to abandon their use. The topic is closed. --add-* forever. -------------- next part -------------- An HTML attachment was scrubbed... URL: From adinn at redhat.com Wed Jan 15 10:25:04 2025 From: adinn at redhat.com (Andrew Dinn) Date: Wed, 15 Jan 2025 10:25:04 +0000 Subject: [External] : Re: How to open a package from a module in the boot layer to a module in another layer? In-Reply-To: References: <97a53f4d-2e15-4c2c-a21e-7fb0468f4195@oracle.com> <87b70d59-8b43-4cc7-b22e-b47780b6873b@oracle.com> <9cb2b530-39d2-4f29-81b1-5ab923597195@redhat.com> Message-ID: On 15/01/2025 09:37, Code Ranger wrote: > Andrew, thank you for you this example. From https://github.com/ > bytemanproject/byteman (if this is the project you are talking about): > > Byteman supports injection of side effects into Java programs for the > purpose of *tracing *and *testing* application behaviour. It is mostly used at test time. However, it is quite often used for live monitoring of production deployments and, in rare cases, it is resorted to for debugging performance or functional issues when they arise in such deployments. > No, I am sure, using agents to add open/export to a module from the boot > layer can hardly be called an optimal and elegant solution. Well, we all have our own standards of elegance and also of what risks we are willing to take . . . > Therefore, I decided to abandon their use. The topic is closed. --add-* > forever. Like I said . . . ;-) regards, Andrew Dinn ----------- Red Hat Distinguished Engineer Red Hat UK Ltd Registered in England and Wales under Company Registration No. 03798903 Directors: Michael Cunningham, Michael ("Mike") O'Neill From coderanger2025 at outlook.com Thu Jan 16 00:28:34 2025 From: coderanger2025 at outlook.com (Code Ranger) Date: Thu, 16 Jan 2025 02:28:34 +0200 Subject: Does opens/exports moduleA.X to moduleB work when moduleB is in other layer? Message-ID: Please, consider the following situation: The boot layer contains moduleA, which has the following line in module-info: "opens com.company.a.foo to com.google.gson;" The child layer contains gson. And this is what I get: java.lang.reflect.InaccessibleObjectException: Unable to make field private ... com.company.a.foo.Bar accessible: moduleA does not "opens com.company.a.foo" to module com.google.gson If I do "opens com.company.a.foo;" then everything works fine, but it is not what I would like to do. Can someone confirm if this is expected behavior? Is this a bug, or does opens/exports moduleA.X to moduleB only work when moduleA and moduleB are in the same layer? Best regards, CR From alan.bateman at oracle.com Thu Jan 16 09:52:42 2025 From: alan.bateman at oracle.com (Alan Bateman) Date: Thu, 16 Jan 2025 09:52:42 +0000 Subject: Does opens/exports moduleA.X to moduleB work when moduleB is in other layer? In-Reply-To: References: Message-ID: <616f8275-cc3c-42ff-a02e-a553f5f823d1@oracle.com> On 16/01/2025 00:28, Code Ranger wrote: > Please, consider the following situation: > > The boot layer contains moduleA, which has the following line in > module-info: "opens com.company.a.foo to com.google.gson;" > The child layer contains gson. > > And this is what I get: > > java.lang.reflect.InaccessibleObjectException: Unable to make field > private ... com.company.a.foo.Bar accessible: moduleA does not "opens > com.company.a.foo" to module com.google.gson > > If I do "opens com.company.a.foo;" then everything works fine, but it > is not what I would like to do. > > Can someone confirm if this is expected behavior? Is this a bug, or > does opens/exports moduleA.X to moduleB only work when moduleA and > moduleB are in the same layer? Assuming com.google.gson wasn't observable at compile-time, then I assume you got a warning at compile-time too. When creating a module layer, qualified exports/opens are reified to export or open to the target module in the current or parent layers. Qualified exports to modules that aren't found are ignored. The details are specified in the ModuleLayer class description. So yes, this is expected behavior. Maybe someone familiar with Gson can help but it seems to use "type adapters" for cases like this. If you really need com.google.gson in a child layer doing deep reflection on classes in a parent or boot layer then it require cooperation from code in the parent layer. -Alan From alex.buckley at oracle.com Thu Jan 16 19:06:21 2025 From: alex.buckley at oracle.com (Alex Buckley) Date: Thu, 16 Jan 2025 11:06:21 -0800 Subject: `requires static` versus service binding In-Reply-To: <55e20d98-bb8f-41a5-bc41-6735bdae4e5a@oracle.com> References: <34f95d77-c081-4d26-b61c-adab76e151c0@oracle.com> <55e20d98-bb8f-41a5-bc41-6735bdae4e5a@oracle.com> Message-ID: On 1/13/2025 9:37 AM, Alan Bateman wrote: > `requires static` was added to support annotations that aren't needed at > runtime, and also some configuration cases. I don't think support for > optional service interfaces has been ruled out but it's more complex to > specify that it might appear. Alan and I have been discussing resolution of services that were present at compile time but are missing at run time. See the comments in https://bugs.openjdk.org/browse/JDK-8299504 (bearing in mind that the Java Bug System now shows newest-first by default). As Alan says, this is a complex matter because of `transitive` dependencies and qualified exports. It reasons about relationships between entities declared in the program (modules) in a way that is more reminiscent of language design than library design. We think we've got the shape of things nailed down, but continue to polish it. Alex From david.lloyd at redhat.com Thu Jan 16 19:22:07 2025 From: david.lloyd at redhat.com (David Lloyd) Date: Thu, 16 Jan 2025 13:22:07 -0600 Subject: `requires static` versus service binding In-Reply-To: References: <34f95d77-c081-4d26-b61c-adab76e151c0@oracle.com> <55e20d98-bb8f-41a5-bc41-6735bdae4e5a@oracle.com> Message-ID: On Thu, Jan 16, 2025 at 1:07?PM Alex Buckley wrote: > On 1/13/2025 9:37 AM, Alan Bateman wrote: > > `requires static` was added to support annotations that aren't needed at > > runtime, and also some configuration cases. I don't think support for > > optional service interfaces has been ruled out but it's more complex to > > specify that it might appear. > > Alan and I have been discussing resolution of services that were present > at compile time but are missing at run time. See the comments in > https://bugs.openjdk.org/browse/JDK-8299504 (bearing in mind that the > Java Bug System now shows newest-first by default). > > As Alan says, this is a complex matter because of `transitive` > dependencies and qualified exports. It reasons about relationships > between entities declared in the program (modules) in a way that is more > reminiscent of language design than library design. We think we've got > the shape of things nailed down, but continue to polish it. > It's too bad there aren't modifiers for uses/provides which could have been used to (for example) mark them as `static` or something like that. But, it's looking good so far IMO. A change along the lines of what's proposed should work for any use case I can think up. -- - DML ? he/him -------------- next part -------------- An HTML attachment was scrubbed... URL: From coderanger2025 at outlook.com Fri Jan 31 13:18:25 2025 From: coderanger2025 at outlook.com (Code Ranger) Date: Fri, 31 Jan 2025 15:18:25 +0200 Subject: How to export a package from a module in a boot layer to module in a child layer. Message-ID: Hello all. I have a boot layer with `org.fusesource.jansi` module a child layer with jline3 module. Jline3 wants to use jansi: Caused by: java.lang.IllegalAccessError: class org.jline.terminal.impl.jansi.JansiTerminalProvider (in module org.jline) cannot access class org.fusesource.jansi.internal.Kernel32 (in module org.fusesource.jansi) because module org.fusesource.jansi does not export org.fusesource.jansi.internal to module org.jline ?? ?at org.jline at 3.28.0/org.jline.terminal.impl.jansi.JansiTerminalProvider.verifyAtLeast(JansiTerminalProvider.java:85) ~[jline-3.28.0.jar:?] ?? ?at org.jline at 3.28.0/org.jline.terminal.impl.jansi.JansiTerminalProvider.(JansiTerminalProvider.java:93) ~[jline-3.28.0.jar:?] ?? ?at java.base/jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:62) ~[?:?] ?? ?at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:502) ~[?:?] ?? ?at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:486) ~[?:?] ?? ?at org.jline at 3.28.0/org.jline.terminal.spi.TerminalProvider.load(TerminalProvider.java:69) ~[jline-3.28.0.jar:?] If I do ??? --add-exports org.fusesource.jansi/org.fusesource.jansi.internal=org.jline \ I get WARNING: Unknown module: org.jline specified to --add-exports (as I was already told if a module is not the boot layer it is just ignored) if I do ??? --add-exports org.fusesource.jansi/org.fusesource.jansi.internal=ALL-UNNAMED \ I get the same exception. Could anyone say how to fix it? Best regards, CR From david.lloyd at redhat.com Fri Jan 31 15:30:10 2025 From: david.lloyd at redhat.com (David Lloyd) Date: Fri, 31 Jan 2025 09:30:10 -0600 Subject: How to export a package from a module in a boot layer to module in a child layer. In-Reply-To: References: Message-ID: AFAIK it cannot be done with `jansi` in your boot layer. One solution would be to put it into a child layer, which will allow you to access the `Controller` for it, which you can then use to add the export manually after defining the `jline3` module in its sub-layer. Otherwise, `jansi` would have to cooperatively call `Module.addExports` for your module, which seems unlikely to me. On Fri, Jan 31, 2025 at 7:19?AM Code Ranger wrote: > Hello all. > > I have a boot layer with `org.fusesource.jansi` module a child layer with > jline3 module. Jline3 wants to use jansi: > > Caused by: java.lang.IllegalAccessError: class > org.jline.terminal.impl.jansi.JansiTerminalProvider (in module org.jline) > cannot access class org.fusesource.jansi.internal.Kernel32 (in module > org.fusesource.jansi) because module org.fusesource.jansi does not export > org.fusesource.jansi.internal to module org.jline > at org.jline at 3.28.0/org.jline.terminal.impl.jansi.JansiTerminalProvider.verifyAtLeast(JansiTerminalProvider.java:85) > ~[jline-3.28.0.jar:?] > at org.jline at 3.28.0/org.jline.terminal.impl.jansi.JansiTerminalProvider.(JansiTerminalProvider.java:93) > ~[jline-3.28.0.jar:?] > at > java.base/jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:62) > ~[?:?] > at > java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:502) > ~[?:?] > at > java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:486) > ~[?:?] > at org.jline at 3.28.0/org.jline.terminal.spi.TerminalProvider.load(TerminalProvider.java:69) > ~[jline-3.28.0.jar:?] > > If I do > --add-exports > org.fusesource.jansi/org.fusesource.jansi.internal=org.jline \ > > I get WARNING: Unknown module: org.jline specified to --add-exports > (as I was already told if a module is not the boot layer it is just > ignored) > > if I do > --add-exports > org.fusesource.jansi/org.fusesource.jansi.internal=ALL-UNNAMED \ > > I get the same exception. > > Could anyone say how to fix it? > > Best regards, CR > > -- - DML ? he/him -------------- next part -------------- An HTML attachment was scrubbed... URL: From coderanger2025 at outlook.com Fri Jan 31 16:49:04 2025 From: coderanger2025 at outlook.com (Code Ranger) Date: Fri, 31 Jan 2025 18:49:04 +0200 Subject: How to export a package from a module in a boot layer to module in a child layer. In-Reply-To: References: Message-ID: Thank you for your suggestion. jansi should be placed in the boot layer, because it is also used by log4j2, that also should be in the boot layer. I think (I may be wrong, because I am not a JPMS guru like jigsaw team members) the problem arises due to two serious constraints: 1. we don't have access to the boot layer controller and we received a categorical refusal to grant access to it. 2. qualified opens/exports doesn't work to child layers. For example, I can't?even open an issue in jansi project to open internal package to jline because it gives nothing in this situation. Best regards,CR On 1/31/25 17:30, David Lloyd wrote: > AFAIK it cannot be done with `jansi` in your boot layer. One solution would be to put it into a child layer, which will allow you to access the `Controller` for it, which you can then use to add the export manually after defining the `jline3` module in its sub-layer. Otherwise, `jansi` would have to cooperatively call `Module.addExports` for your module, which seems unlikely to me. > > On Fri, Jan 31, 2025 at 7:19?AM Code Ranger wrote: > > Hello all. > > I have a boot layer with `org.fusesource.jansi` module a child layer with jline3 module. Jline3 wants to use jansi: > > Caused by: java.lang.IllegalAccessError: class org.jline.terminal.impl.jansi.JansiTerminalProvider (in module org.jline) cannot access class org.fusesource.jansi.internal.Kernel32 (in module org.fusesource.jansi) because module org.fusesource.jansi does not export org.fusesource.jansi.internal to module org.jline > ??? ?at org.jline at 3.28.0/org.jline.terminal.impl.jansi.JansiTerminalProvider.verifyAtLeast(JansiTerminalProvider.java:85) ~[jline-3.28.0.jar:?] > ??? ?at org.jline at 3.28.0/org.jline.terminal.impl.jansi.JansiTerminalProvider.(JansiTerminalProvider.java:93) ~[jline-3.28.0.jar:?] > ??? ?at java.base/jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:62) ~[?:?] > ??? ?at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:502) ~[?:?] > ??? ?at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:486) ~[?:?] > ??? ?at org.jline at 3.28.0/org.jline.terminal.spi.TerminalProvider.load(TerminalProvider.java:69) ~[jline-3.28.0.jar:?] > > If I do > ???? --add-exports org.fusesource.jansi/org.fusesource.jansi.internal=org.jline \ > > I get WARNING: Unknown module: org.jline specified to --add-exports > (as I was already told if a module is not the boot layer it is just ignored) > > if I do > ???? --add-exports org.fusesource.jansi/org.fusesource.jansi.internal=ALL-UNNAMED \ > > I get the same exception. > > Could anyone say how to fix it? > > Best regards, CR > > > > -- > - DML ? he/him -------------- next part -------------- An HTML attachment was scrubbed... URL: From ron.pressler at oracle.com Fri Jan 31 17:23:22 2025 From: ron.pressler at oracle.com (Ron Pressler) Date: Fri, 31 Jan 2025 17:23:22 +0000 Subject: How to export a package from a module in a boot layer to module in a child layer. In-Reply-To: References: Message-ID: > On 31 Jan 2025, at 16:49, Code Ranger wrote: > > > 1. we don't have access to the boot layer controller and we received a categorical refusal to grant access to it. That is incorrect. The API for controlling modules in the boot layer has been available since JDK 9, using the very mechanism that has been used for precisely this kind of super-powered manipulation for 20 years: https://docs.oracle.com/en/java/javase/23/docs/api/java.instrument/java/lang/instrument/Instrumentation.html#redefineModule(java.lang.Module,java.util.Set,java.util.Map,java.util.Map,java.util.Set,java.util.Map) ? Ron From coderanger2025 at outlook.com Fri Jan 31 17:33:44 2025 From: coderanger2025 at outlook.com (Code Ranger) Date: Fri, 31 Jan 2025 19:33:44 +0200 Subject: How to export a package from a module in a boot layer to module in a child layer. In-Reply-To: References: Message-ID: On 1/31/25 19:23, Ron Pressler wrote: >> On 31 Jan 2025, at 16:49, Code Ranger wrote: >> >> >> 1. we don't have access to the boot layer controller and we received a categorical refusal to grant access to it. > That is incorrect. The API for controlling modules in the boot layer has been available since JDK 9, using the very mechanism that has been used for precisely this kind of super-powered manipulation for 20 years: > > https://docs.oracle.com/en/java/javase/23/docs/api/java.instrument/java/lang/instrument/Instrumentation.html#redefineModule(java.lang.Module,java.util.Set,java.util.Map,java.util.Map,java.util.Set,java.util.Map) Unfortunately, this is correct. I am sure, that if it is necessary to use agent and java instrumentation to make this the simplest configuration work, then it simply means, that something is wrong here. Maybe two many constrains? Best regards, CR -------------- next part -------------- An HTML attachment was scrubbed... URL: From ron.pressler at oracle.com Fri Jan 31 17:54:52 2025 From: ron.pressler at oracle.com (Ron Pressler) Date: Fri, 31 Jan 2025 17:54:52 +0000 Subject: How to export a package from a module in a boot layer to module in a child layer. In-Reply-To: References: Message-ID: <49C51157-9FB6-4DFA-A375-C168469194F0@oracle.com> > On 31 Jan 2025, at 17:33, Code Ranger wrote: > > > > On 1/31/25 19:23, Ron Pressler wrote: >> >> >>> On 31 Jan 2025, at 16:49, Code Ranger wrote: >>> >>> >>> 1. we don't have access to the boot layer controller and we received a categorical refusal to grant access to it. >>> >> That is incorrect. The API for controlling modules in the boot layer has been available since JDK 9, using the very mechanism that has been used for precisely this kind of super-powered manipulation for 20 years: >> >> https://docs.oracle.com/en/java/javase/23/docs/api/java.instrument/java/lang/instrument/Instrumentation.html#redefineModule(java.lang.Module,java.util.Set,java.util.Map,java.util.Map,java.util.Set,java.util.Map) >> > Unfortunately, this is correct. > > I am sure, that if it is necessary to use agent and java instrumentation to make this the simplest configuration work, then it simply means, that something is wrong here. Maybe two many constrains? Manipulating a module?s access checks at runtime allows you, for example, to redefine the value of 5 in Java to be 6, and that is precisely the job agents are, and have always been, for. Changing the internal rules by which the runtime operates ? and modules? access are at the core of these rules ? is the very definition of low-level instrumentation. Have you encontered a difficulty using this standard approach? From alex.buckley at oracle.com Fri Jan 31 18:24:59 2025 From: alex.buckley at oracle.com (Alex Buckley) Date: Fri, 31 Jan 2025 10:24:59 -0800 Subject: How to export a package from a module in a boot layer to module in a child layer. In-Reply-To: References: Message-ID: <8f513235-54ba-414a-b836-b97b7b7359aa@oracle.com> It seems the JLine maintainers were concerned about depending on the internals of a separate project (jansi), because "to minimize the maintenance cost, Jansi has been merged into JLine 3.25." (https://github.com/jline/jline3). That's a good step because it saves people who are not maintainers of JLine from trying to make it work by messing with the internals of a standalone jansi JAR. Even better, JLine 3.24 started using its own providers to access the Windows API, rather than go through its bundled version of jansi. This means that on modern JDKs, JLine can use the FFM API to make native Windows calls. I expect that the performance and maintainability of this approach is light years ahead of the old clunky route through jansi.internal.Kernel32. It's hard to see why anyone using JLine 3.28 (per the errors below) would want to use an external version of jansi when the JLine maintainers have done such great work to ensure no-one has to worry about jansi. Alex On 1/31/2025 5:18 AM, Code Ranger wrote: > Hello all. > > I have a boot layer with `org.fusesource.jansi` module a child layer > with jline3 module. Jline3 wants to use jansi: > > Caused by: java.lang.IllegalAccessError: class > org.jline.terminal.impl.jansi.JansiTerminalProvider (in module > org.jline) cannot access class org.fusesource.jansi.internal.Kernel32 > (in module org.fusesource.jansi) because module org.fusesource.jansi > does not export org.fusesource.jansi.internal to module org.jline > ?? ?at org.jline at 3.28.0/ > org.jline.terminal.impl.jansi.JansiTerminalProvider.verifyAtLeast(JansiTerminalProvider.java:85) ~[jline-3.28.0.jar:?] > ?? ?at org.jline at 3.28.0/ > org.jline.terminal.impl.jansi.JansiTerminalProvider.(JansiTerminalProvider.java:93) ~[jline-3.28.0.jar:?] > ?? ?at java.base/ > jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:62) ~[?:?] > ?? ?at java.base/ > java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:502) ~[?:?] > ?? ?at java.base/ > java.lang.reflect.Constructor.newInstance(Constructor.java:486) ~[?:?] > ?? ?at org.jline at 3.28.0/ > org.jline.terminal.spi.TerminalProvider.load(TerminalProvider.java:69) > ~[jline-3.28.0.jar:?] > > If I do > ??? --add-exports org.fusesource.jansi/ > org.fusesource.jansi.internal=org.jline \ > > I get WARNING: Unknown module: org.jline specified to --add-exports > (as I was already told if a module is not the boot layer it is just > ignored) > > if I do > ??? --add-exports org.fusesource.jansi/ > org.fusesource.jansi.internal=ALL-UNNAMED \ > > I get the same exception. > > Could anyone say how to fix it? > > Best regards, CR > From coderanger2025 at outlook.com Fri Jan 31 18:25:00 2025 From: coderanger2025 at outlook.com (Code Ranger) Date: Fri, 31 Jan 2025 20:25:00 +0200 Subject: How to export a package from a module in a boot layer to module in a child layer. In-Reply-To: <49C51157-9FB6-4DFA-A375-C168469194F0@oracle.com> References: <49C51157-9FB6-4DFA-A375-C168469194F0@oracle.com> Message-ID: On 1/31/25 19:54, Ron Pressler wrote: >> >> Unfortunately, this is correct. >> >> I am sure, that if it is necessary to use agent and java instrumentation to make this the simplest configuration work, then it simply means, that something is wrong here. Maybe two many constrains? > Manipulating a module?s access checks at runtime allows you, for example, to redefine the value of 5 in Java to be 6, and that is precisely the job agents are, and have always been, for. Changing the internal rules by which the runtime operates ? and modules? access are at the core of these rules ? is the very definition of low-level instrumentation. > > Have you encontered a difficulty using this standard approach? Unfortunately, I cannot consider your example appropriate for the situation under discussion. We are not talking about changing 5 to 6, but rather about granting or modifying access to a module?s packages. By other words, I don't need 5 to be 6, I just need jline to work with jansi? Do you see the difference? If the only solution is to use agent and there is no other normal, standard, elegant solution I want to be sure of it. Because, if this is the only solution then the following statement will be true - "If you have two layers and the most common library modules, to make it work YOU NEED TO USE AGENT AND JAVA INSTRUMENTATION". Something like that. Best regards, CR From ron.pressler at oracle.com Fri Jan 31 19:07:56 2025 From: ron.pressler at oracle.com (Ron Pressler) Date: Fri, 31 Jan 2025 19:07:56 +0000 Subject: How to export a package from a module in a boot layer to module in a child layer. In-Reply-To: References: <49C51157-9FB6-4DFA-A375-C168469194F0@oracle.com> Message-ID: <9CC07A23-4041-43DD-BD06-99F3EFAB0D6A@oracle.com> > On 31 Jan 2025, at 18:25, Code Ranger wrote: > > > > On 1/31/25 19:54, Ron Pressler wrote: >>> >>> Unfortunately, this is correct. >>> >>> I am sure, that if it is necessary to use agent and java instrumentation to make this the simplest configuration work, then it simply means, that something is wrong here. Maybe two many constrains? >> Manipulating a module?s access checks at runtime allows you, for example, to redefine the value of 5 in Java to be 6, and that is precisely the job agents are, and have always been, for. Changing the internal rules by which the runtime operates ? and modules? access are at the core of these rules ? is the very definition of low-level instrumentation. >> >> Have you encontered a difficulty using this standard approach? > Unfortunately, I cannot consider your example appropriate for the situation under discussion. We are not talking about changing 5 to 6, but rather about granting or modifying access to a module?s packages. By other words, I don't need 5 to be 6, I just need jline to work with jansi? Do you see the difference? > > If the only solution is to use agent and there is no other normal, standard, elegant solution I want to be sure of it. Using agents is and has always been the normal and standard solutions when Java?s internal rules and meaning are to be changed. Changing the inner workings of the JDK, however, is not elegant (no matter how it?s done), and is, therefore, done sparingly. When you ask for the power to change the value of 5 into 6 ? which is what you?re asking for when you want to modify access to modules ? it doesn?t matter whether or not you actually use that power. The runtime now must be aware that it cannot assume 5 means 5 anymore. If you encounter a problem and come to believe that the only solution is to change the internal assumptions that the Java runtime wants to rely on, then yes, agents are the mechanism to achieve that. But the problem here isn?t what you want. You?re saying that there is a basic library that cannot work unless Java's internal assumptions are changed. It?s easy to see that a library that asks that the laws of Java be changed for it to work is a problematic library. That?s the problem that needs to be solved. If indeed, as Alex writes, JLine?s authors have fixed the core issue, then it already has been solved. > > Because, if this is the only solution then the following statement will be true - "If you have two layers and the most common library modules, to make it work YOU NEED TO USE AGENT AND JAVA INSTRUMENTATION". > Something like that. Your question seems to contain an assumption that AGENTS AND JAVA INSTRUMENTATION are somehow more intrusive or radical than "granting or modifying access to a module?s packages?. That is simply not the case. They are both equally intrusive and radical (it?s possible that code that can do the latter may be able to turn itself into an agent). To give you another exmaple, if you modify java.base?s access, the runtime cannot assume that any string in the entire program is immutable. ? Ron