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?