using @GrabConfig(systemClassLoader=true) in a ScriptEngine

Per Nyfelt <[email protected]> Tue, 8 Jul 2025 12:51:29 +0200
Newsgroups gmane.comp.lang.groovy.user
Message-ID <CAOAt0KSf2Vs8E4amQUapwhBnCMtfuqZoY5An1WtJxutFFZWwOw@mail.gmail.com>
--000000000000cb8c6a063968be43
Content-Type: text/plain; charset="UTF-8"

Hi,

I am trying to figure out a way to use @GrabConfig(systemClassLoader=true)
in a ScritpEngine (or GroovyShell, does not matter.

The following script works without any problem using the groovy command
(.e.g `groovy sqltaskExample.groovy`):

@GrabConfig(systemClassLoader=true)
@Grab('com.h2database:h2:2.3.232')
import groovy.ant.AntBuilder

println "Groovy ClassLoader: ${this.class.classLoader}"
def project = new AntBuilder()
project.with {
  sql(
      driver:     "org.h2.Driver",
      url:        "jdbc:h2:mem:AZ",
      userid:     "sa",
      password:   "",
      // direct printed output into a text file:
      output:     "query.out",
      print:      "yes",      // enable printing of result sets
      showheaders:"false",    // suppress column names
      showtrailers:"false"    // suppress "N rows returned" line
  ) {
    transaction("""
            CREATE TABLE some_table (
              id   INT,
              name VARCHAR(200)
            );
          """)
    transaction("""
            INSERT INTO some_table (id, name)
            VALUES (1, 'hello');
          """)
    transaction("""
            SELECT name
            FROM some_table
            WHERE id = 1;
          """)
  }
  // now the file query.out contains exactly "hello"
  loadfile(property: "row1col1", srcFile: "query.out")
  echo(message: 'row1col1 = ${row1col1}')
  delete(file: "query.out")
}


Calling that from java however does not work:, e.g.

public class ShellWithGrabSupport {
  public static void main(String[] args) throws Exception {
    GroovyScriptEngine gse = new GroovyScriptEngine(".");
    gse.run("sqltaskExample.groovy", new Binding());
  }
}

Results in "No Suitable classloader found for Grab"
I have tried stuff like this:

System.setProperty("groovy.grape.enable", "true");
System.setProperty("groovy.grape.report.downloads", "true");
GroovyClassLoader gcl = new
GroovyClassLoader(ClassLoader.getSystemClassLoader());

CompilerConfiguration config = new CompilerConfiguration();
config.setRecompileGroovySource(true);

GroovyShell shell = new GroovyShell(gcl, config);
Script s = shell.parse(new File("sqltaskExample.groovy"));
s.run();


and

System.setProperty("groovy.grape.report.downloads", "true");
System.setProperty("groovy.grape.enable", "true");
// Ensure system classloader is used
Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader());

// This mimics what the `groovy` CLI does
GroovyMain.main(new String[]{"sqltaskExample.groovy"});


All with the same result.

I use the following to bootstrap java:

gl="$GROOVY_HOME/lib"
v="4.0.27"
cp="$gl/groovy-$v.jar:$gl/groovy-ant-$v.jar:$gl/groovy-ant-$v.jar:$gl/ant-1.10.15.jar:\
$gl/ant-launcher-1.10.15.jar:$gl/ivy-2.5.3.jar"
java -cp "$cp" ShellWithGrabSupport.java


So since ant is loaded by the system classloader, I must
use @GrabConfig(systemClassLoader=true) in the groovy script for the jdbc
driver, otherwise the sql ant task will not be able to find it.

This minimum, reproducible example is here:
https://github.com/perNyfelt/groovy-issues/tree/main/grabconfig

The details of the error are as follows:
Exception in thread "main"
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup
failed:
General error during conversion: No suitable ClassLoader found for grab

java.lang.RuntimeException: No suitable ClassLoader found for grab
        at groovy.grape.GrapeIvy.chooseClassLoader(GrapeIvy.groovy:179)
        at groovy.grape.GrapeIvy.grab(GrapeIvy.groovy:273)
        at groovy.grape.Grape$1.run(Grape.java:172)
        at groovy.grape.Grape$1.run(Grape.java:158)
        at
java.base/java.security.AccessController.doPrivileged(AccessController.java:319)
        at groovy.grape.Grape.grab(Grape.java:158)
        at
groovy.grape.GrabAnnotationTransformation.visit(GrabAnnotationTransformation.java:380)
        at
org.codehaus.groovy.transform.ASTTransformationVisitor.lambda$addPhaseOperationsForGlobalTransforms$5(ASTTransformationVisitor.java:374)
        at
org.codehaus.groovy.control.CompilationUnit$ISourceUnitOperation.doPhaseOperation(CompilationUnit.java:906)
        at
org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:701)
        at
org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:675)
        at
groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:365)
        at
groovy.lang.GroovyClassLoader.lambda$parseClass$2(GroovyClassLoader.java:314)
        at
org.codehaus.groovy.runtime.memoize.StampedCommonCache.compute(StampedCommonCache.java:163)
        at
org.codehaus.groovy.runtime.memoize.StampedCommonCache.getAndPut(StampedCommonCache.java:154)
        at
groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:314)
        at
groovy.util.GroovyScriptEngine$ScriptClassLoader.doParseClass(GroovyScriptEngine.java:231)
        at
groovy.util.GroovyScriptEngine$ScriptClassLoader.parseClass(GroovyScriptEngine.java:218)
        at
groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:298)
        at
groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:263)
        at
groovy.util.GroovyScriptEngine.loadScriptByName(GroovyScriptEngine.java:534)
        at
groovy.util.GroovyScriptEngine.createScript(GroovyScriptEngine.java:584)
        at groovy.util.GroovyScriptEngine.run(GroovyScriptEngine.java:571)
        at ShellWithGrabSupport.main(ShellWithGrabSupport.java:7)
        at
...
Does anyone know a way?

--000000000000cb8c6a063968be43
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">Hi,=C2=A0<div><br></div><div>I am trying to figure out a w=
ay to use=C2=A0@GrabConfig(systemClassLoader=3Dtrue) in a ScritpEngine=C2=
=A0(or GroovyShell, does not matter.</div><div><br></div><div>The=C2=A0foll=
owing script works without any problem using the groovy command (.e.g `groo=
vy sqltaskExample.groovy`):<br><br><div style=3D"background-color:rgb(30,31=
,34);color:rgb(188,190,196)"><pre style=3D"font-family:&quot;JetBrains Mono=
&quot;,monospace"><span style=3D"color:rgb(179,174,96)">@GrabConfig</span>(=
systemClassLoader=3D<span style=3D"color:rgb(207,142,109)">true</span>)<br>=
<span style=3D"color:rgb(179,174,96)">@Grab</span>(<span style=3D"color:rgb=
(106,171,115)">&#39;com.h2database:h2:2.3.232&#39;</span>)<br><span style=
=3D"color:rgb(207,142,109)">import </span>groovy.ant.AntBuilder<br><br>prin=
tln <span style=3D"color:rgb(106,171,115)">&quot;Groovy ClassLoader: </span=
>$<span style=3D"font-weight:bold">{</span><span style=3D"color:rgb(207,142=
,109)">this</span>.<span style=3D"color:rgb(199,125,187)">class</span>.<spa=
n style=3D"color:rgb(199,125,187)">classLoader</span><span style=3D"font-we=
ight:bold">}</span><span style=3D"color:rgb(106,171,115)">&quot;<br></span>=
<span style=3D"color:rgb(207,142,109)">def </span>project =3D <span style=
=3D"color:rgb(207,142,109)">new </span>AntBuilder()<br>project.<span style=
=3D"color:rgb(117,122,133)">with </span><span style=3D"font-weight:bold">{<=
br></span><span style=3D"font-weight:bold">  </span><span style=3D"color:rg=
b(117,122,133)">sql</span>(<br>      <span style=3D"color:rgb(106,171,115)"=
>driver</span>:     <span style=3D"color:rgb(106,171,115)">&quot;org.h2.Dri=
ver&quot;</span>,<br>      <span style=3D"color:rgb(106,171,115)">url</span=
>:        <span style=3D"color:rgb(106,171,115)">&quot;jdbc:h2:mem:AZ&quot;=
</span>,<br>      <span style=3D"color:rgb(106,171,115)">userid</span>:    =
 <span style=3D"color:rgb(106,171,115)">&quot;sa&quot;</span>,<br>      <sp=
an style=3D"color:rgb(106,171,115)">password</span>:   <span style=3D"color=
:rgb(106,171,115)">&quot;&quot;</span>,<br>      <span style=3D"color:rgb(1=
22,126,133)">// direct printed output into a text file:<br></span><span sty=
le=3D"color:rgb(122,126,133)">      </span><span style=3D"color:rgb(106,171=
,115)">output</span>:     <span style=3D"color:rgb(106,171,115)">&quot;quer=
y.out&quot;</span>,<br>      <span style=3D"color:rgb(106,171,115)">print</=
span>:      <span style=3D"color:rgb(106,171,115)">&quot;yes&quot;</span>, =
     <span style=3D"color:rgb(122,126,133)">// enable printing of result se=
ts<br></span><span style=3D"color:rgb(122,126,133)">      </span><span styl=
e=3D"color:rgb(106,171,115)">showheaders</span>:<span style=3D"color:rgb(10=
6,171,115)">&quot;false&quot;</span>,    <span style=3D"color:rgb(122,126,1=
33)">// suppress column names<br></span><span style=3D"color:rgb(122,126,13=
3)">      </span><span style=3D"color:rgb(106,171,115)">showtrailers</span>=
:<span style=3D"color:rgb(106,171,115)">&quot;false&quot;    </span><span s=
tyle=3D"color:rgb(122,126,133)">// suppress &quot;N rows returned&quot; lin=
e<br></span><span style=3D"color:rgb(122,126,133)">  </span>) <span style=
=3D"font-weight:bold">{<br></span><span style=3D"font-weight:bold">    </sp=
an><span style=3D"color:rgb(117,122,133)">transaction</span>(<span style=3D=
"color:rgb(106,171,115)">&quot;&quot;&quot;<br></span><span style=3D"color:=
rgb(106,171,115)">            CREATE TABLE some_table (<br></span><span sty=
le=3D"color:rgb(106,171,115)">              id   INT,<br></span><span style=
=3D"color:rgb(106,171,115)">              name VARCHAR(200)<br></span><span=
 style=3D"color:rgb(106,171,115)">            );<br></span><span style=3D"c=
olor:rgb(106,171,115)">          &quot;&quot;&quot;</span>)<br>    <span st=
yle=3D"color:rgb(117,122,133)">transaction</span>(<span style=3D"color:rgb(=
106,171,115)">&quot;&quot;&quot;<br></span><span style=3D"color:rgb(106,171=
,115)">            INSERT INTO some_table (id, name)<br></span><span style=
=3D"color:rgb(106,171,115)">            VALUES (1, &#39;hello&#39;);<br></s=
pan><span style=3D"color:rgb(106,171,115)">          &quot;&quot;&quot;</sp=
an>)<br>    <span style=3D"color:rgb(117,122,133)">transaction</span>(<span=
 style=3D"color:rgb(106,171,115)">&quot;&quot;&quot;<br></span><span style=
=3D"color:rgb(106,171,115)">            SELECT name<br></span><span style=
=3D"color:rgb(106,171,115)">            FROM some_table<br></span><span sty=
le=3D"color:rgb(106,171,115)">            WHERE id =3D 1;<br></span><span s=
tyle=3D"color:rgb(106,171,115)">          &quot;&quot;&quot;</span>)<br>  <=
span style=3D"font-weight:bold">}<br></span><span style=3D"font-weight:bold=
">  </span><span style=3D"color:rgb(122,126,133)">// now the file query.out=
 contains exactly &quot;hello&quot;<br></span><span style=3D"color:rgb(122,=
126,133)">  </span><span style=3D"color:rgb(117,122,133)">loadfile</span>(<=
span style=3D"color:rgb(106,171,115)">property</span>: <span style=3D"color=
:rgb(106,171,115)">&quot;row1col1&quot;</span>, <span style=3D"color:rgb(10=
6,171,115)">srcFile</span>: <span style=3D"color:rgb(106,171,115)">&quot;qu=
ery.out&quot;</span>)<br>  <span style=3D"color:rgb(117,122,133)">echo</spa=
n>(<span style=3D"color:rgb(106,171,115)">message</span>: <span style=3D"co=
lor:rgb(106,171,115)">&#39;row1col1 =3D ${row1col1}&#39;</span>)<br>  <span=
 style=3D"color:rgb(117,122,133)">delete</span>(<span style=3D"color:rgb(10=
6,171,115)">file</span>: <span style=3D"color:rgb(106,171,115)">&quot;query=
.out&quot;</span>)<br><span style=3D"font-weight:bold">}</span></pre></div>=
</div><div><br></div><div>Calling that from java however does not work:, e.=
g.<br><div style=3D"background-color:rgb(30,31,34);color:rgb(188,190,196)">=
<pre style=3D"font-family:&quot;JetBrains Mono&quot;,monospace"><span style=
=3D"color:rgb(207,142,109)">public class </span>ShellWithGrabSupport {<br> =
 <span style=3D"color:rgb(207,142,109)">public static void </span><span sty=
le=3D"color:rgb(86,168,245)">main</span>(String[] args) <span style=3D"colo=
r:rgb(207,142,109)">throws </span>Exception {<br>    GroovyScriptEngine gse=
 =3D <span style=3D"color:rgb(207,142,109)">new </span>GroovyScriptEngine(<=
span style=3D"color:rgb(106,171,115)">&quot;.&quot;</span>);<br>    gse.run=
(<span style=3D"color:rgb(106,171,115)">&quot;sqltaskExample.groovy&quot;</=
span>, <span style=3D"color:rgb(207,142,109)">new </span>Binding());<br>  }=
<br>}</pre></div>Results in &quot;No Suitable classloader found for Grab&qu=
ot;</div><div>I have tried stuff like this:<br><div style=3D"background-col=
or:rgb(30,31,34);color:rgb(188,190,196)"><pre style=3D"font-family:&quot;Je=
tBrains Mono&quot;,monospace">System.<span style=3D"font-style:italic">setP=
roperty</span>(<span style=3D"color:rgb(106,171,115)">&quot;groovy.grape.en=
able&quot;</span>, <span style=3D"color:rgb(106,171,115)">&quot;true&quot;<=
/span>);<br>System.<span style=3D"font-style:italic">setProperty</span>(<sp=
an style=3D"color:rgb(106,171,115)">&quot;groovy.grape.report.downloads&quo=
t;</span>, <span style=3D"color:rgb(106,171,115)">&quot;true&quot;</span>);=
<br>GroovyClassLoader gcl =3D <span style=3D"color:rgb(207,142,109)">new </=
span>GroovyClassLoader(ClassLoader.<span style=3D"font-style:italic">getSys=
temClassLoader</span>());<br><br>CompilerConfiguration config =3D <span sty=
le=3D"color:rgb(207,142,109)">new </span>CompilerConfiguration();<br>config=
.setRecompileGroovySource(<span style=3D"color:rgb(207,142,109)">true</span=
>);<br><br>GroovyShell shell =3D <span style=3D"color:rgb(207,142,109)">new=
 </span>GroovyShell(gcl, config);<br>Script s =3D shell.parse(<span style=
=3D"color:rgb(207,142,109)">new </span>File(<span style=3D"color:rgb(106,17=
1,115)">&quot;sqltaskExample.groovy&quot;</span>));<br>s.run();</pre></div>=
</div><div><br></div><div>and</div><div><div style=3D"background-color:rgb(=
30,31,34);color:rgb(188,190,196)"><pre style=3D"font-family:&quot;JetBrains=
 Mono&quot;,monospace">System.<span style=3D"font-style:italic">setProperty=
</span>(<span style=3D"color:rgb(106,171,115)">&quot;groovy.grape.report.do=
wnloads&quot;</span>, <span style=3D"color:rgb(106,171,115)">&quot;true&quo=
t;</span>);<br>System.<span style=3D"font-style:italic">setProperty</span>(=
<span style=3D"color:rgb(106,171,115)">&quot;groovy.grape.enable&quot;</spa=
n>, <span style=3D"color:rgb(106,171,115)">&quot;true&quot;</span>);<br><sp=
an style=3D"color:rgb(122,126,133)">// Ensure system classloader is used<br=
></span>Thread.<span style=3D"font-style:italic">currentThread</span>().set=
ContextClassLoader(ClassLoader.<span style=3D"font-style:italic">getSystemC=
lassLoader</span>());<br><br><span style=3D"color:rgb(122,126,133)">// This=
 mimics what the `groovy` CLI does<br></span>GroovyMain.<span style=3D"font=
-style:italic">main</span>(<span style=3D"color:rgb(207,142,109)">new </spa=
n>String[]{<span style=3D"color:rgb(106,171,115)">&quot;sqltaskExample.groo=
vy&quot;</span>});</pre></div></div><div><br></div><div>All with the same r=
esult.=C2=A0</div><br class=3D"gmail-Apple-interchange-newline">I use the f=
ollowing to bootstrap java:<div><div style=3D"background-color:rgb(30,31,34=
);color:rgb(188,190,196)"><pre style=3D"font-family:&quot;JetBrains Mono&qu=
ot;,monospace">gl=3D<span style=3D"color:rgb(106,171,115)">&quot;</span>$GR=
OOVY_HOME<span style=3D"color:rgb(106,171,115)">/lib&quot;<br></span>v=3D<s=
pan style=3D"color:rgb(106,171,115)">&quot;4.0.27&quot;<br></span>cp=3D<spa=
n style=3D"color:rgb(106,171,115)">&quot;</span>$gl<span style=3D"color:rgb=
(106,171,115)">/groovy-</span>$v<span style=3D"color:rgb(106,171,115)">.jar=
:</span>$gl<span style=3D"color:rgb(106,171,115)">/groovy-ant-</span>$v<spa=
n style=3D"color:rgb(106,171,115)">.jar:</span>$gl<span style=3D"color:rgb(=
106,171,115)">/groovy-ant-</span>$v<span style=3D"color:rgb(106,171,115)">.=
jar:</span>$gl<span style=3D"color:rgb(106,171,115)">/ant-1.10.15.jar:\<br>=
</span>$gl<span style=3D"color:rgb(106,171,115)">/ant-launcher-1.10.15.jar:=
</span>$gl<span style=3D"color:rgb(106,171,115)">/ivy-2.5.3.jar&quot;<br></=
span><span style=3D"color:rgb(197,118,51)">java </span>-cp <span style=3D"c=
olor:rgb(106,171,115)">&quot;</span>$cp<span style=3D"color:rgb(106,171,115=
)">&quot; </span>ShellWithGrabSupport.java</pre></div></div><div><br></div>=
<div>So since ant is loaded by the system classloader, I must use=C2=A0@Gra=
bConfig(systemClassLoader=3Dtrue) in the groovy script for the jdbc driver,=
 otherwise the sql ant task will not be able to find it.</div><div><br></di=
v><div>This minimum, reproducible=C2=A0example is here:=C2=A0<a href=3D"htt=
ps://github.com/perNyfelt/groovy-issues/tree/main/grabconfig">https://githu=
b.com/perNyfelt/groovy-issues/tree/main/grabconfig</a></div><div><br></div>=
<div>The details of the error are as follows:<br>Exception in thread &quot;=
main&quot; org.codehaus.groovy.control.MultipleCompilationErrorsException: =
startup failed:<br>General error during conversion: No suitable ClassLoader=
 found for grab<br><br>java.lang.RuntimeException: No suitable ClassLoader =
found for grab<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 at groovy.grape.GrapeIvy.choo=
seClassLoader(GrapeIvy.groovy:179)<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 at groovy=
.grape.GrapeIvy.grab(GrapeIvy.groovy:273)<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 at=
 groovy.grape.Grape$1.run(Grape.java:172)<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 at=
 groovy.grape.Grape$1.run(Grape.java:158)<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 at=
 java.base/java.security.AccessController.doPrivileged(AccessController.jav=
a:319)<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 at groovy.grape.Grape.grab(Grape.java=
:158)<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 at groovy.grape.GrabAnnotationTransfor=
mation.visit(GrabAnnotationTransformation.java:380)<br>=C2=A0 =C2=A0 =C2=A0=
 =C2=A0 at org.codehaus.groovy.transform.ASTTransformationVisitor.lambda$ad=
dPhaseOperationsForGlobalTransforms$5(ASTTransformationVisitor.java:374)<br=
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 at org.codehaus.groovy.control.CompilationUnit=
$ISourceUnitOperation.doPhaseOperation(CompilationUnit.java:906)<br>=C2=A0 =
=C2=A0 =C2=A0 =C2=A0 at org.codehaus.groovy.control.CompilationUnit.process=
PhaseOperations(CompilationUnit.java:701)<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 at=
 org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:6=
75)<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 at groovy.lang.GroovyClassLoader.doParse=
Class(GroovyClassLoader.java:365)<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 at groovy.=
lang.GroovyClassLoader.lambda$parseClass$2(GroovyClassLoader.java:314)<br>=
=C2=A0 =C2=A0 =C2=A0 =C2=A0 at org.codehaus.groovy.runtime.memoize.StampedC=
ommonCache.compute(StampedCommonCache.java:163)<br>=C2=A0 =C2=A0 =C2=A0 =C2=
=A0 at org.codehaus.groovy.runtime.memoize.StampedCommonCache.getAndPut(Sta=
mpedCommonCache.java:154)<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 at groovy.lang.Gro=
ovyClassLoader.parseClass(GroovyClassLoader.java:314)<br>=C2=A0 =C2=A0 =C2=
=A0 =C2=A0 at groovy.util.GroovyScriptEngine$ScriptClassLoader.doParseClass=
(GroovyScriptEngine.java:231)<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 at groovy.util=
.GroovyScriptEngine$ScriptClassLoader.parseClass(GroovyScriptEngine.java:21=
8)<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 at groovy.lang.GroovyClassLoader.parseCla=
ss(GroovyClassLoader.java:298)<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 at groovy.lan=
g.GroovyClassLoader.parseClass(GroovyClassLoader.java:263)<br>=C2=A0 =C2=A0=
 =C2=A0 =C2=A0 at groovy.util.GroovyScriptEngine.loadScriptByName(GroovyScr=
iptEngine.java:534)<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 at groovy.util.GroovyScr=
iptEngine.createScript(GroovyScriptEngine.java:584)<br>=C2=A0 =C2=A0 =C2=A0=
 =C2=A0 at groovy.util.GroovyScriptEngine.run(GroovyScriptEngine.java:571)<=
br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 at ShellWithGrabSupport.main(ShellWithGrabSu=
pport.java:7)<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 at=C2=A0</div><div>...</div><d=
iv>Does anyone know a way?<br><br><br></div><div><br></div></div>

--000000000000cb8c6a063968be43--