CLOVER🍀

That was when it all began.

GroovyからJSR-223(ScriptEngine)を使ってGroovyを呼ぶ

小ネタ系エントリ。

Groovyでちょっとした作業をこなすためのスクリプトを書いていて、設定ファイル的なものを読み込ませて処理を切り替えたいと思った時に、こんなことをしてみましたよということで。

Groovyで設定ファイルを使うなら、ConfigSlurperというものが便利らしいです。

ConfigSlurper
http://groovy.codehaus.org/ConfigSlurper

でも、できれば処理そのものをクラス定義して切り替えたいなぁと思い、JSR-223を使うことにしました。

つまり、こういうこと。

呼び出し元。
caller.groovy

import javax.script.ScriptEngineManager

def manager = new ScriptEngineManager()
def engine = manager.getEngineByName('Groovy')

def helloClass = engine.eval(new File('hello.groovy').text)
def hello = helloClass.newInstance()

hello.say()

呼び出される側。
hello.groovy

class Hello {
    def say() {
        println('Hello Groovy!')
    }
}

ScriptEngine#eval時にClassクラスが返ってきているようなので

def helloClass = engine.eval(new File('hello.groovy').text)

これをnewInstanceして実行しました。

def hello = helloClass.newInstance()

で、実際に自分が使った時には、こんな感じでインターフェースを設けて使ってみました。
launcher.groovy

import javax.script.ScriptEngineManager

def manager = new ScriptEngineManager()
def engine = manager.getEngineByName('Groovy')

def executeScripts = args

executeScripts.each { script ->
     def executorClass = engine.eval(new File(script).text)
     def executor = executorClass.newInstance()

     executor.execute()
}

interface Executor {
    public void execute()
}

呼び出される側。
executors/hello-executor.groovy

class HelloExecutor implements Executor {
    @Override
    public void execute() {
        println('Hello Groovy!')
    }
}

executors/greet-executor.groovy

class GreetExecutor implements Executor {
    @Override
    public void execute() {
        println('Greeting!!')
    }
}

ディレクトリ構成はこんな感じ。

$ find launcher.groovy executors
launcher.groovy
executors
executors/hello-executor.groovy
executors/greet-executor.groovy

実行。

$ groovy launcher.groovy executors/hello-executor.groovy executors/greet-executor.groovy 
Hello Groovy!
Greeting!!

定義したインターフェースが見えているようで、メソッドのオーバーライドがなかったりするとちゃんとエラーになってくれます。
*ダックタイピングでやってもいいわけですが…

小さなスクリプト用途なので、あんまり大仰な仕組みは要らないけど、定義だけじゃなくて実装も書きたいということでこんな方法を選びました。

…普通ならこうやる的な見落としがあるかもと思いつつ、ですが。