简体   繁体   中英

How to use import inside a dynamically loaded groovy file

I am trying to come up with a way for my users to supply plugins into the main groovy application by dynamically loading their source file. But their groovy file contains import statements and I don't know how to make them work even with an apparently good classpath.

The main application is a shell script, bin/top.sh:

#!/bin/bash
groovy-2.4.1/bin/groovy -cp lib lib/Top.groovy

The lib/Top.groovy class:

public class Top {
  public static void main(String[] args) {
    ClassLoader parent = getClass().getClassLoader()
    GroovyClassLoader loader = new GroovyClassLoader(parent)
    Class groovyClass = loader.parseClass(new File("UserPlugin.groovy"))
    GroovyObject groovyObject = (GroovyObject) groovyClass.newInstance()
    groovyObject.invokeMethod("run",args)
  } 
}

The user class UserPlugin.groovy:

// The following import can be found in the classpath
// passed by the shell script (under lib/, next to Top.groovy)
import Lib

class UserPlugin {
  def UserPlugin() {
    Lib lib = new Lib()
  }
  def run(String [] args) {
    println("Running with: "+args)
  }
}

And the lib/Lib.groovy:

class Lib {
  def Lib() {
    println("Lib")
  }
}

When I run with bin/top.sh , I get: UserPlugin.groovy: 3: unable to resolve class Lib

When I add lib to the class loader like so loader.addClasspath('lib') , it's rather catastrophic:

org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
General error during class generation: java.lang.NoClassDefFoundError: groovy/lang/GroovyObject

java.lang.RuntimeException: java.lang.NoClassDefFoundError: groovy/lang/GroovyObject
    at org.codehaus.groovy.control.CompilationUnit.convertUncaughtExceptionToCompilationError(CompilationUnit.java:1088)

How can this work while keeping it all scripted and not compiled? Is this even possible?

Sorry I don't have time to find the bug but I think the problem is with the setting of the context classloader. GroovyShell.run takes care of that for you which I recommend over replicating that code.

Top.groovy

    public class Top {
        public static void main(String[] args) {
            new GroovyShell().run(new File("UserPlugin.groovy"), args)
        }
    }

If you're willing to make Top.groovy a script rather than class then you can do this:

Top.groovy

    run(new File("UserPlugin.groovy"), args)

The UserPlugin.groovy then needs to be either a class (with a main method) or a script to use the standard Groovy calling logic.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM