From alan.bateman at oracle.com Wed Oct 8 17:39:32 2025 From: alan.bateman at oracle.com (Alan Bateman) Date: Wed, 8 Oct 2025 18:39:32 +0100 Subject: ModuleLayer for java.base only In-Reply-To: <8916454.NyiUUSuA9g@lintel> References: <8916454.NyiUUSuA9g@lintel> Message-ID: <22971ee5-2327-4964-9250-cc0c3b35a2ea@oracle.com> On 08/10/2025 06:19, Jaroslav Tulach wrote: > Dear JPMS experts! > > I am currently working at Enso developing runtime for _dual representation > (visual and textual) programming language_ [Enso](https://urldefense.com/v3/__https://github.com/enso-org/__;!!ACWV5N9M2RV99hQ!MSZoD63gQltbiD0s6RtcgnXj1LJG0hqBQb84MygtZ7LKRGpELc0ZURO2QOh0lZjT8PhyJ4QCjYOv2G3AvcdF32JDTpk$ > enso/). Enso uses JVM for its operating system interoperability - as such we > are packaging our runtime, as well as Enso libraries as modular JAR files. > Basically we need a _modular runtime container_ with JPMS... > > And here comes the question: Is there a way to create `ModuleLayer` for just > `java.base`? > > Enso runtime obviously needs many other JDK & co. modules. However I don't > want to expose them to the Enso library module JARs (possibly coming from 3rd > party sources) - I'd like them to use only `java.base` and not randomly poke > around for other Enso runtime module JAR files. > > Is there a way to do it? I failed to find it. Googling it out yields no > relevant results and I don't like the idea of chatting with an AI. I'd rather > talk to the experts - hence I am writing to you! > > - I can get `ModuleLayer.boot()` - but that contains too many modules - for > example `org.enso.runner` & co. which I' do not want to expose > - I can get `ModuleLayer.empty()` - but that one is a bit "too empty" > - I tried to create own layer with `ModuleLayer.empty()` as parent and put > `ModuleFinder.ofSystem()` and `java.base` module in... > - but I am getting various errors related to classloaders - "java.base must > be loaded by system classloader" - etc. > - in short: I haven't found a way to get thru and construct `java.base` only > layer > > How that is supposed to work? How do I create a `ModuleLayer` with just > `java.base` and control what the Enso library JARs can access? Can I control > that regardless of how the JVM was initialized? There must a a way, right? Or > am I asking for too much encapsulation? I think what you are looking for is to create the Configuration for a child layer in a way that "hides" all but java.base from the modules in the parent configuration. There isn't a way to do this as resolution time. That is, if the configuration for the parent/boot has java.base, enso, and apache.foo (used by enso) then there is no way to have resolution fail if a user module requires enso or requires apache.foo. Who creates the configuration for the child layer? Can it process the Configuration and fail if any module in the configurations reads a module other than java.base? -Alan From michal at kleczek.org Wed Oct 8 18:06:13 2025 From: michal at kleczek.org (=?utf-8?Q?Micha=C5=82_K=C5=82eczek?=) Date: Wed, 8 Oct 2025 20:06:13 +0200 Subject: ModuleLayer for java.base only In-Reply-To: <22971ee5-2327-4964-9250-cc0c3b35a2ea@oracle.com> References: <8916454.NyiUUSuA9g@lintel> <22971ee5-2327-4964-9250-cc0c3b35a2ea@oracle.com> Message-ID: > On 8 Oct 2025, at 19:39, Alan Bateman wrote: > > > > On 08/10/2025 06:19, Jaroslav Tulach wrote: >> >> How that is supposed to work? How do I create a `ModuleLayer` with just >> `java.base` and control what the Enso library JARs can access? Can I control >> that regardless of how the JVM was initialized? There must a a way, right? Or >> am I asking for too much encapsulation? > I think what you are looking for is to create the Configuration for a child layer in a way that "hides" all but java.base from the modules in the parent configuration. There isn't a way to do this as resolution time. That is, if the configuration for the parent/boot has java.base, enso, and apache.foo (used by enso) then there is no way to have resolution fail if a user module requires enso or requires apache.foo. > > Who creates the configuration for the child layer? Can it process the Configuration and fail if any module in the configurations reads a module other than java.base? Another approach would be to have only a closed ?bootstrap" module in module path. It would provide main class, initialize a module layer with all Enzo modules and their dependencies, and pass execution to it. Since bootstrap module does not export anything and is closed, having it in a boot layer would be harmless. The downside is that with such setup there is no way to package Enzo and its dependencies in runtime image generated by jpackage. ? Michal From michal at kleczek.org Thu Oct 9 06:29:16 2025 From: michal at kleczek.org (=?utf-8?Q?Micha=C5=82_K=C5=82eczek?=) Date: Thu, 9 Oct 2025 08:29:16 +0200 Subject: ModuleLayer for java.base only In-Reply-To: <47855697.fMDQidcC6G@lintel> References: <8916454.NyiUUSuA9g@lintel> <22971ee5-2327-4964-9250-cc0c3b35a2ea@oracle.com> <47855697.fMDQidcC6G@lintel> Message-ID: > On 8 Oct 2025, at 20:54, Jaroslav Tulach wrote: > > On st?eda 8. ??jna 2025 20:06:13, st?edoevropsk? letn? ?as, Micha? K?eczek > wrote: >>> On 8 Oct 2025, at 19:39, Alan Bateman wrote: >>> >>> On 08/10/2025 06:19, Jaroslav Tulach wrote: >>>> How that is supposed to work? How do I create a `ModuleLayer` with just >>>> `java.base` and control what the Enso library JARs can access? Can I >>>> control that regardless of how the JVM was initialized? There must a a >>>> way, right? Or am I asking for too much encapsulation? >>> >>> I think what you are looking for is to create the Configuration for a >>> child layer in a way that "hides" all but java.base from the modules in >>> the parent configuration. There isn't a way to do this as resolution >>> time. That is, if the configuration for the parent/boot has java.base, >>> enso, and apache.foo (used by enso) then there is no way to have >>> resolution fail if a user module requires enso or requires apache.foo. >>> >>> Who creates the configuration for the child layer? Can it process the >>> Configuration and fail if any module in the configurations reads a module >>> other than java.base? >> Another approach would be to have only a closed ?bootstrap" module in module >> path. > > Thanks for your reply, Micha?. > > This solution might work for Enso application and yes, I am considering to go > this route. E.g. to alter boootstrap path to > > >> ... provide main class, initialize a module layer with all Enzo >> modules and their dependencies, and pass execution to it. > > However, Enso isn't just an application, but a language component embeddable > into other Java applications. In such situation Enso isn't in control of the > JVM bootstrap and cannot perform this kind of equilibristic. If you make the embedding application link to only the Enso bootstrap module would solve the issue, wouldn?t it? Encapsulating internals of Enso can be achieved by simply putting it in a single module and not exporting anything. (Or you can use ?export ? to ?? if you really need multi-module Enso) So I understand your real goal is to insulate users of Enso from versions of its dependencies. In case of embedding Enso it is then responsibility of the embedding application - it has to make sure its own dependencies do not interfere with modules it loads. ? Michal From michal at kleczek.org Thu Oct 9 06:29:16 2025 From: michal at kleczek.org (=?utf-8?Q?Micha=C5=82_K=C5=82eczek?=) Date: Thu, 9 Oct 2025 08:29:16 +0200 Subject: ModuleLayer for java.base only In-Reply-To: <47855697.fMDQidcC6G@lintel> References: <8916454.NyiUUSuA9g@lintel> <22971ee5-2327-4964-9250-cc0c3b35a2ea@oracle.com> <47855697.fMDQidcC6G@lintel> Message-ID: > On 8 Oct 2025, at 20:54, Jaroslav Tulach wrote: > > On st?eda 8. ??jna 2025 20:06:13, st?edoevropsk? letn? ?as, Micha? K?eczek > wrote: >>> On 8 Oct 2025, at 19:39, Alan Bateman wrote: >>> >>> On 08/10/2025 06:19, Jaroslav Tulach wrote: >>>> How that is supposed to work? How do I create a `ModuleLayer` with just >>>> `java.base` and control what the Enso library JARs can access? Can I >>>> control that regardless of how the JVM was initialized? There must a a >>>> way, right? Or am I asking for too much encapsulation? >>> >>> I think what you are looking for is to create the Configuration for a >>> child layer in a way that "hides" all but java.base from the modules in >>> the parent configuration. There isn't a way to do this as resolution >>> time. That is, if the configuration for the parent/boot has java.base, >>> enso, and apache.foo (used by enso) then there is no way to have >>> resolution fail if a user module requires enso or requires apache.foo. >>> >>> Who creates the configuration for the child layer? Can it process the >>> Configuration and fail if any module in the configurations reads a module >>> other than java.base? >> Another approach would be to have only a closed ?bootstrap" module in module >> path. > > Thanks for your reply, Micha?. > > This solution might work for Enso application and yes, I am considering to go > this route. E.g. to alter boootstrap path to > > >> ... provide main class, initialize a module layer with all Enzo >> modules and their dependencies, and pass execution to it. > > However, Enso isn't just an application, but a language component embeddable > into other Java applications. In such situation Enso isn't in control of the > JVM bootstrap and cannot perform this kind of equilibristic. If you make the embedding application link to only the Enso bootstrap module would solve the issue, wouldn?t it? Encapsulating internals of Enso can be achieved by simply putting it in a single module and not exporting anything. (Or you can use ?export ? to ?? if you really need multi-module Enso) So I understand your real goal is to insulate users of Enso from versions of its dependencies. In case of embedding Enso it is then responsibility of the embedding application - it has to make sure its own dependencies do not interfere with modules it loads. ? Michal From alan.bateman at oracle.com Thu Oct 9 10:07:17 2025 From: alan.bateman at oracle.com (Alan Bateman) Date: Thu, 9 Oct 2025 11:07:17 +0100 Subject: ModuleLayer for java.base only In-Reply-To: <3165226.BEx9A2HvPv@lintel> References: <8916454.NyiUUSuA9g@lintel> <22971ee5-2327-4964-9250-cc0c3b35a2ea@oracle.com> <3165226.BEx9A2HvPv@lintel> Message-ID: On 08/10/2025 20:11, Jaroslav Tulach wrote: > From a rationalistic perspective, I am looking for something very different: > > I'd like to start from scratch - e.g. `ModuleLayer.empty()` and built > something on top of it myself. E.g. create a layer with > `ModuleFinder.ofSystem()` where I include only some JDK modules - like > `java.base` (but certainly not `org.graalvm.collections`). > > Why that isn't possible? > > Is there a technical problem in creating multiple layers that would all > contain `java.base`? > > Or I am just first one who's asking for a feature like this? There can only be one instance of java.base in the runtime, in the same way that there is one java.lang.Object class. You are right that Configuration.empty() and ModuleLayer.empty() are not interesting outside of creating the boot layer or tests. It is possible to start with `--limit-modules java.base` so that the boot layer only contains java.base but you cannot stack module layers that contain the platform modules. There are technical and non-technical issues that prevent the java.* name space being used by custom class loaders, and it's not possible to give away control of the boot or platform class loaders without introducing major security + integrity risk. The original requirements for Project Jigsaw did envisage allowing some means to augment the set of platform modules at runtime but it hasn't been a priority to work on. The mundane cases that have been important is the dynamic loading of the java.instrument and java.management modules, something that is done in a very limited and controlled manner in response to commands that load tool agents. As regards your desire to hide Enso, and the modules that it uses, from applications then it is something that has come once or twice, usually in the context of some container/application server that wants to hide its dependences from applications that it launches. The module system does not provide this type of isolation. -Alan -------------- next part -------------- An HTML attachment was scrubbed... URL: From j.michelberger at gmail.com Mon Oct 20 19:48:58 2025 From: j.michelberger at gmail.com (Joerg Michelberger) Date: Mon, 20 Oct 2025 21:48:58 +0200 Subject: JImage missing in ToolProvider registration Message-ID: Hi there, this is J?rg, the one who met Stuart Marks at Devoxx BE 2025. We talked at Devoxx Antwerp about a flaw with the programmatic accessibility of jimage in JDK21. While it was with source/target 8 possible to compile and access the Main of jlink/jimage/jmod, encapsulation with source/target 11 it is not. But the intended new ToolProvider API which should make the three accessible in a controlled way, lacks the Tool Registration of jimage. Registration for jmod can be seen here: https://github.com/openjdk/jdk/blob/master/src/jdk.jlink/share/classes/jdk/tools/jmod/Main.java#L53, same for jlink. But jimage seems to be forgotten: https://github.com/openjdk/jdk/blob/master/src/jdk.jlink/share/classes/jdk/tools/jimage/Main.java . IMHO it is trivial to add registration for the jimage in code and module definition and it seems that it also could be almost riskless to be backported to JDK25/17/11. This would make me as the "nobody use that" user happy, because it feels so bad to access this via ProcessBuilder and external process call. Withdrawn ticket in OpenJDK is here: https://bugs.openjdk.org/browse/JDK-8359429. I already cloned the OpenJdk Github repo to provide a pull request to provide the fix, but it seems I am not familiar enough with the contribution process and so on. As Stuart mentioned the question in the JDK-8359429 issue comment, I tried the Chuck Norris --add-opens and also accessing JImageTask instead of its Main class, but with no success. And here is a hint for the question in the issue comment for Alan Bateman. I have a somewhat unusual deployment process and have several checks in place to ensure that there are all classes for the deployment target on board and are deployed for a certain installation. The check scans among other things all META-INF/services if service interface and service implementations are part of the deployed classes in jars and modules. To do that, the jimage list command with the module file of the with the app deployed target JRE is used to gather the list of the JRE classes. Thanks a lot. Regards. J?rg Michelberger -------------- next part -------------- An HTML attachment was scrubbed... URL: From alan.bateman at oracle.com Tue Oct 21 07:27:54 2025 From: alan.bateman at oracle.com (Alan Bateman) Date: Tue, 21 Oct 2025 08:27:54 +0100 Subject: JImage missing in ToolProvider registration In-Reply-To: References: Message-ID: <65802e6a-9f47-4233-a52e-917a861bd72f@oracle.com> On 20/10/2025 20:48, Joerg Michelberger wrote: > Hi there, > this is J?rg, the one who met Stuart Marks at Devoxx BE 2025. > > We talked at Devoxx Antwerp about a flaw with the programmatic > accessibility of jimage in JDK21. > > While it was with source/target 8 possible to compile and access the > Main of jlink/jimage/jmod, encapsulation with source/target 11 it is > not. But the intended new ToolProvider API which should make the three > accessible in a controlled way, lacks the Tool Registration of jimage. > > Registration for jmod can be seen here: > https://github.com/openjdk/jdk/blob/master/src/jdk.jlink/share/classes/jdk/tools/jmod/Main.java#L53, > same for jlink. But jimage seems to be forgotten: > https://github.com/openjdk/jdk/blob/master/src/jdk.jlink/share/classes/jdk/tools/jimage/Main.java. > > IMHO it is trivial to add registration for the jimage in code and > module definition and it seems that it also could be almost riskless > to be backported to JDK25/17/11. The jimage tool is included in the JDK is for troubleshooting scenarios, e.g. corrupt installations, allow support engineers extract class files when hurting a bug or crash involving custom run-time images with modified JDK classes or non-JDK modules. It's not a tool that we would expect to see used by developers or used in builds. This is why this tool does not have a man page and why the tool is not registered with ToolProvider for "in-process" usages. So very different to tools such as javac, javadoc, jar, jmod, jlink ... that are good candidates to use with the ToolProvider API. I think it would be useful if you could say a bit more about what you are looking to do with the jimage tool. Are you just tooling for a way to run all tools in bin "in-process" or is this something more real where you are using the jimage tool to do something specific. -Alan