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



Reply via email to