Nashorn JavaScript Invocable.getInterface在Web应用程序中的类加载器中失败

时间:2015-07-28 07:08:52

标签: java classloader nashorn scriptengine javascript-engine

我需要从Java代码调用(使用Nashorn)JavaScript中定义的函数并传递一些参数。而不是使用Invocable.invokeFunction(“Foo”,arg1,arg2),我打算定义一个接口,然后请求Invocable来生成它的实现,就像Oracle建议here,“嵌入Oracle Nashorn”:

package mypackage;
public final class MyClass {
  public interface Composer {
    void compose(final StringBuilder subject, final StringBuilder body);
  }

  public void composeEmail(...) {
      ...
      final ScriptEngineManager engineManager = new ScriptEngineManager();
      final ScriptEngine engine = engineManager.getEngineByName("nashorn");
      engine.eval(scriptText);
      final Invocable invocable = (Invocable) engine;
      final Composer composer = (Composer)invocable.getInterface(Composer);
      composer.compose(subject, body);
      ...
  }
}

问题是,因为我在Tomcat中运行的Web应用程序中执行此操作,所以我的Composer由app级别的类加载器加载,而nashorn类则由扩展类加载器加载。所以getInterface无法说出 TypeError:找不到ScriptObject和mypackage.Composer的公共类加载器

任何想法如何克服?当然,我可以尝试在父类加载器中加载Composer,假设(类似黑客)它实际上是一个ext加载器,但至少有一个问题:它无法找到我的类。我认为这是非常正确的:我的软件包位于我的Web应用程序中,扩展加载程序看起来并不存在。还有其他很棒的想法吗?

P.S。现在我注意到这个消息很奇怪:如果app类加载器委托给ext类加载器,那么后者当然是它们的通用类加载器。也许他们试图说目标接口的类加载器必须等于实际实现的类加载器,或者实现的类加载器必须委托给目标(但反之亦然)?

1 个答案:

答案 0 :(得分:2)

Create an instance of jdk.nashorn.api.scripting.NashornScriptEngineFactory directly instead of doing engineManager.engineByName(), then create a ScriptEngine by invoking NashornScriptEngineFactory.getScriptEngine(ClassLoader appLoader) and passing it your app-level loader.