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?

Reply via email to