ScriptEngineManagerのコンストラクタにClassLoaderを与えても、スクリプトがそのClassLoaderの元で動作するわけではない。


[intlink id=”190″]でScriptEngineManagerを生成するときにClassLoaderを設定できるようなことを書きました。実験しているうちに、そんなに甘くないことがわかりました。

実験コード

クラスローダ(=tClassLoader)を作って、そこからクラス(=OTL)のインスタンスをnewしてみる。
その後で、スクリプトでも同じようにインスタンスをnewしてみる。

public class ScriptEngineClassLoaderTest {
  public static void main(String[] aArguments) throws MalformedURLException, ClassNotFoundException, ScriptException {
    URLClassLoader tClassLoader = new URLClassLoader(new URL[] { new URL("file:../testtest/bin/") });
    System.out.println("load: " + tClassLoader.loadClass("OTL"));
    System.out.println("--------- スクリプトエンジンで new してみる ---------");
    ScriptEngineManager tScriptEngineManager = new ScriptEngineManager(tClassLoader);
    tScriptEngineManager.getEngineByName("groovy").eval("new OTL();");
  }
}

実行結果

load: class OTL
--------- スクリプトエンジンで new してみる ---------
Exception in thread "main" javax.script.ScriptException: org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed, Script1.groovy: 1: unable to resolve class OTL
 @ line 1, column 1.
1 error

  at com.sun.script.groovy.GroovyScriptEngine.eval(GroovyScriptEngine.java:114)
  at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:247)
  at jp.kurusugawa.benchmark.scriptengine.ScriptEngineClassLoaderTest.main(ScriptEngineClassLoaderTest.java:16)
Caused by: org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed, Script1.groovy: 1: unable to resolve class OTL
 @ line 1, column 1.
1 error

  at org.codehaus.groovy.control.ErrorCollector.failIfErrors(ErrorCollector.java:326)
  at org.codehaus.groovy.control.CompilationUnit.applyToSourceUnits(CompilationUnit.java:847)
  at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:476)
  at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:309)
  at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:279)
  at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:274)
  at com.sun.script.groovy.GroovyScriptEngine.getScriptClass(GroovyScriptEngine.java:275)
  at com.sun.script.groovy.GroovyScriptEngine.eval(GroovyScriptEngine.java:108)
  ... 2 more

クラス(=OTL)が見つからないそうです。

javascriptでも試す。

    tScriptEngineManager.getEngineByName("javascript").eval("new OTL();");
load: class OTL
--------- スクリプトエンジンで new してみる ---------
Exception in thread "main" javax.script.ScriptException: sun.org.mozilla.javascript.internal.EcmaError: ReferenceError: "OTL" is not defined. (#1) in  at line number 1
  at com.sun.script.javascript.RhinoScriptEngine.eval(RhinoScriptEngine.java:110)
  at com.sun.script.javascript.RhinoScriptEngine.eval(RhinoScriptEngine.java:124)
  at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:247)
  at jp.kurusugawa.benchmark.scriptengine.ScriptEngineClassLoaderTest.main(ScriptEngineClassLoaderTest.java:16)

やっぱり見つからない・・・orz

コンストラクタに指定するClassLoaderの役割は

と言うわけで、ScriptEngineManagerのコンストラクタにClassLoaderを与えても、スクリプト実行時のClassLoaderは差し替えれないようです。
では、ScriptEngineManagerのコンストラクタに与えるClassLoaderはどういう意味を持っているのかというと?

public class ScriptEngineClassLoaderTest {
  public static void main(String[] args) throws MalformedURLException {
    System.out.println("ClassLoaderを指定しないと・・・");
    System.out.println("engine: " + new ScriptEngineManager().getEngineByName("groovy"));

    System.out.println("ClassLoaderを指定すれば・・・");
    System.out.println("engine: " + new ScriptEngineManager(new URLClassLoader(new URL[] { new URL("file:../groovy-engine/bin/") })).getEngineByName("groovy"));
  }
}
ClassLoaderを指定しないと・・・
engine: null
ClassLoaderを指定すれば・・・
engine: com.sun.script.groovy.GroovyScriptEngine@b6ece5

ScriptEngine自体のClassLoaderが指定できると言うことでした。
めちゃめちゃガッカリ。

カテゴリー: 技術情報