On 29.03.25 12:18, Mirco Colletta wrote:
Hi all, I'd like to know if some of you has experience on how to create a full modular (JPMS, JSR 376) groovy application.
>
First of all, is it possible, at the moment, to create a full modular groovy application? If yes, what is the recommended approach?
the question though is what full modular means. Getting my knowledge about modules refreshed a bit... we have normal modules, automatic modules and unnamed modules. Groovy comes as automatic module, so it can be referenced by name, but does not follow all the rules named modules do. Latest JVMs might have done relevant changes here of course. Then there are the two cases of a script run by Groovy from source and precompiled Groovy code in a different module. I think running scripts works to some extend, a full fledged Groovy app in a module... maybe not. [...]
running the app using the NON modular (gradle) build file it works just fine: (Gradle v. 8.13) gradle --build-file=build.gradle.nm runApp but as you can see this solution is not ideal nor elegant due to these jvmArgs "--add-exports" to all unnamed modules (the many exports are extracted from my real project) https://github.com/mcolletta/groovy-modular-example/blob/main/build.gradle.nm <https://github.com/mcolletta/groovy-modular-example/blob/main/build.gradle.nm>
yes... that is exactly what I expected :(
Eventually I've tried a different approach. I created a /module-info.java/ file with all the necessary "requires", including requires org.apache.groovy; https://github.com/mcolletta/groovy-modular-example/blob/main/src/main/java/module-info.java <https://github.com/mcolletta/groovy-modular-example/blob/main/src/main/java/module-info.java> this way the application somewhat compiles with: gradle build https://github.com/mcolletta/groovy-modular-example/blob/main/build.gradle <https://github.com/mcolletta/groovy-modular-example/blob/main/build.gradle> but for strange reasons it starts to give very weird errors at runtime when /enums /are present gradle run Caused by: java.lang.ExceptionInInitializerError at io.modular.example/io.modular.example.App <http://io.modular.example.App>.<init>(App.groovy) at java.base/jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:62) ... 11 more Caused by: groovy.lang.GroovyRuntimeException: Could not find matching constructor for: io.modular.example.Mode(String, Integer) at org.apache.groovy@4.0.26/groovy.lang.MetaClassImpl.createCachedConstructor(MetaClassImpl.java:1726) at org.apache.groovy@4.0.26/groovy.lang.MetaClassImpl.selectConstructorAndTransformArguments1(MetaClassImpl.java:1752) at org.apache.groovy@4.0.26/groovy.lang.MetaClassImpl.selectConstructorAndTransformArguments(MetaClassImpl.java:1679) at org.apache.groovy@4.0.26/org.codehaus.groovy.runtime.ScriptBytecodeAdapter.selectConstructorAndTransformArguments(ScriptBytecodeAdapter.java:252) at io.modular.example/io.modular.example.Mode.$INIT(App.groovy) at io.modular.example/io.modular.example.Mode.<clinit>(App.groovy) Here "Mode" is a simple /enum /and the problematic statement is this one: Mode mode = Mode.Edit
actually this line Mode.$INIT(App.groovy) tells me we are in the constructor of Mode, that is not explicitly in the code, but would be related more to the enum definition itself. Even though it is a enum it still looks roughly like this (same in Java): final static class Mode extend Enum { Mode(){super()} ... } The call to super is realized by selectConstructorAndTransformArguments
https://github.com/mcolletta/groovy-modular-example/blob/4f9862d87fedd7a883b358ea0619faa0b5834374/src/main/groovy/io/modular/example/App.groovy#L20 <https://github.com/mcolletta/groovy-modular-example/blob/4f9862d87fedd7a883b358ea0619faa0b5834374/src/main/groovy/io/modular/example/App.groovy#L20>
my assumption is that because of the module system Groovy cannot see the the non-public constructor of the enum. I think you need to add an add-opens... or was it add-exports.... well the groovy modules must be able to read the hidden methods in the module of the groovy app. So maybe opens io.modular.example to org.apache.groovy; in the module info might be already enough?
It seems that in a modular context something interferes with the groovy runtime for (at least) enums.
It could also be solved by using static compilation for the module. But the problem will come back for other places
(Beside the opaque behavior of the "run" task of the application plugin I got however the same error adding my module explicitly with the command line argument --module-path) However as I stated above I'm not sure if this is a lecit and correct strategy to make a groovy modular application. Do you have any suggestions/advice?
We tweaked many places already in preparation for the module system and keep changing things here an there, but we might be missing something somewhere. I am afraid you would be the one to discover that then. We will try to support you of course. Just don't expect things to go easy. bye Jochen