CLOVER🍀

That was when it all began.

JSR-223(Groovy)でGrapeを使う

ちょっと思い立った小ネタとして。

JSR-223でGroovyが使えますが、このスクリプト中でGrapeを使うには?と。

準備

とりあえず、JSR-223でGroovyを動かすには、Maven依存関係に「groovy-jsr223」または「groovy-all」があればOKです。

        <dependency>
            <groupId>org.codehaus.groovy</groupId>
            <artifactId>groovy-jsr223</artifactId>
            <version>2.4.7</version>
        </dependency>
        <!-- groovy-allでも可 -->
        <!--
        <dependency>
            <groupId>org.codehaus.groovy</groupId>
            <artifactId>groovy-all</artifactId>
            <version>2.4.7</version>
        </dependency>
        -->

動作確認にはテストコードで。

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>org.assertj</groupId>
            <artifactId>assertj-core</artifactId>
            <version>3.5.2</version>
        </dependency>

コードを書く

動作確認用のコードは、側はこんな感じに。
src/test/java/org/littlewings/scripting/groovygrape/GroovyScriptingTest.java

package org.littlewings.scripting.groovygrape;

import java.util.Arrays;
import java.util.stream.Collectors;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

import org.junit.Test;

import static org.assertj.core.api.Assertions.assertThat;

public class GroovyScriptingTest {
    // ここにテストを書く
}

とりあえず、ふつうにJSR-223越しにGroovyを使ってみましょう。

    @Test
    public void simpleExecuteGroovy() throws ScriptException {
        ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
        ScriptEngine scriptEngine = scriptEngineManager.getEngineByName("groovy");

        assertThat(scriptEngine.eval("'Hello Groovy'.replace('Groovy', 'World')"))
                .isEqualTo("Hello World");
    }

まあ、ふつうに動きます。

では、スクリプト内にGrapeを使ったコードを仕込んでみます。

    @Test
    public void usingGrapes() throws ScriptException {
        ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
        ScriptEngine scriptEngine = scriptEngineManager.getEngineByName("groovy");

        String script =
                Arrays
                        .asList(
                                "@Grab('org.apache.commons:commons-lang3:3.4')",
                                "import org.apache.commons.lang3.StringUtils",
                                "",
                                "def target = 'Hello World!!!'",
                                "StringUtils.replace(target, 'World', 'Groovy')"
                        )
                        .stream()
                        .collect(Collectors.joining(System.lineSeparator()));

        assertThat(scriptEngine.eval(script))
                .isEqualTo("Hello Groovy!!!");
    }

対象には、Commons Lang 3になってもらいました。

で、動かすとエラーになります。

java.lang.NoClassDefFoundError: org/apache/ivy/core/report/ResolveReport

これを回避するには、依存関係にApache Ivyを加えます。

        <dependency>
            <groupId>org.apache.ivy</groupId>
            <artifactId>ivy</artifactId>
            <version>2.4.0</version>
        </dependency>

Grapeは、Apache Ivyで動いているんでした、と。

こうすると、先ほどのCommons Lang 3を使ったコードはちゃんと動作するようになります。