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:"JetBrains Mono=
",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)">'com.h2database:h2:2.3.232'</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)">"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)">"<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)">"org.h2.Dri=
ver"</span>,<br> <span style=3D"color:rgb(106,171,115)">url</span=
>: <span style=3D"color:rgb(106,171,115)">"jdbc:h2:mem:AZ"=
</span>,<br> <span style=3D"color:rgb(106,171,115)">userid</span>: =
<span style=3D"color:rgb(106,171,115)">"sa"</span>,<br> <sp=
an style=3D"color:rgb(106,171,115)">password</span>: <span style=3D"color=
:rgb(106,171,115)">""</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)">"quer=
y.out"</span>,<br> <span style=3D"color:rgb(106,171,115)">print</=
span>: <span style=3D"color:rgb(106,171,115)">"yes"</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)">"false"</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)">"false" </span><span s=
tyle=3D"color:rgb(122,126,133)">// suppress "N rows returned" 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)">"""<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)"> """</span>)<br> <span st=
yle=3D"color:rgb(117,122,133)">transaction</span>(<span style=3D"color:rgb(=
106,171,115)">"""<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, 'hello');<br></s=
pan><span style=3D"color:rgb(106,171,115)"> """</sp=
an>)<br> <span style=3D"color:rgb(117,122,133)">transaction</span>(<span=
style=3D"color:rgb(106,171,115)">"""<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)"> """</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 "hello"<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)">"row1col1"</span>, <span style=3D"color:rgb(10=
6,171,115)">srcFile</span>: <span style=3D"color:rgb(106,171,115)">"qu=
ery.out"</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)">'row1col1 =3D ${row1col1}'</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)">"query=
.out"</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:"JetBrains Mono",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)">"."</span>);<br> gse.run=
(<span style=3D"color:rgb(106,171,115)">"sqltaskExample.groovy"</=
span>, <span style=3D"color:rgb(207,142,109)">new </span>Binding());<br> }=
<br>}</pre></div>Results in "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:"Je=
tBrains Mono",monospace">System.<span style=3D"font-style:italic">setP=
roperty</span>(<span style=3D"color:rgb(106,171,115)">"groovy.grape.en=
able"</span>, <span style=3D"color:rgb(106,171,115)">"true"<=
/span>);<br>System.<span style=3D"font-style:italic">setProperty</span>(<sp=
an style=3D"color:rgb(106,171,115)">"groovy.grape.report.downloads&quo=
t;</span>, <span style=3D"color:rgb(106,171,115)">"true"</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)">"sqltaskExample.groovy"</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:"JetBrains=
Mono",monospace">System.<span style=3D"font-style:italic">setProperty=
</span>(<span style=3D"color:rgb(106,171,115)">"groovy.grape.report.do=
wnloads"</span>, <span style=3D"color:rgb(106,171,115)">"true&quo=
t;</span>);<br>System.<span style=3D"font-style:italic">setProperty</span>(=
<span style=3D"color:rgb(106,171,115)">"groovy.grape.enable"</spa=
n>, <span style=3D"color:rgb(106,171,115)">"true"</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)">"sqltaskExample.groo=
vy"</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:"JetBrains Mono&qu=
ot;,monospace">gl=3D<span style=3D"color:rgb(106,171,115)">"</span>$GR=
OOVY_HOME<span style=3D"color:rgb(106,171,115)">/lib"<br></span>v=3D<s=
pan style=3D"color:rgb(106,171,115)">"4.0.27"<br></span>cp=3D<spa=
n style=3D"color:rgb(106,171,115)">"</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"<br></=
span><span style=3D"color:rgb(197,118,51)">java </span>-cp <span style=3D"c=
olor:rgb(106,171,115)">"</span>$cp<span style=3D"color:rgb(106,171,115=
)">" </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 "=
main" 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--