Как использовать импорт внутри динамически загружаемого файла Groovy

Я пытаюсь придумать, как мои пользователи могут добавлять плагины в основное приложение Groovy, динамически загружая их исходный файл. Но в их отличном файле содержатся операторы import, и я не знаю, как заставить их работать даже с явно хорошим путем к классам.

Основное приложение - это скрипт оболочки bin/top.sh:

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

Класс lib/Top.groovy:

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)
  } 
}

Пользовательский класс 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)
  }
}

И lib/Lib.groovy:

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

Когда я бегу с bin/top.sh, Я получил: UserPlugin.groovy: 3: unable to resolve class Lib

Когда я добавлю lib к загрузчику классов, как это так loader.addClasspath('lib')Скорее катастрофично:

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)

Как это может работать при сохранении всего сценария, а не скомпилированного? Это вообще возможно?

1 ответ

Решение

Извините, у меня нет времени, чтобы найти ошибку, но я думаю, что проблема в настройке контекстного загрузчика классов. GroovyShell.run позаботится об этом за вас, и я рекомендую использовать его тиражирование.

Top.groovy

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

Если вы хотите сделать Top.groovy сценарием, а не классом, то вы можете сделать это:

Top.groovy

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

Тогда UserPlugin.groovy должен быть либо классом (с основным методом), либо скриптом, чтобы использовать стандартную логику вызова Groovy.

Другие вопросы по тегам