4

我需要从 Java 代码中调用(使用 Nashorn)在 JavaScript 中定义的函数并传递一些参数。我没有使用 Invocable.invokeFunction("Foo", arg1, arg2),而是定义一个接口,然后请求 Invocable 生成它的实现,就像 Oracle在此处建议的那样,“嵌入 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 由应用程序级类加载器加载,而 nashorn 类由扩展类加载器加载。所以 getInterface 失败说TypeError: Can not find a common class loader for ScriptObject and mypackage.Composer

任何想法如何克服?当然,我可以尝试在父类加载器中加载 Composer,假设它实际上是一个 ext 加载器(类似于 hack),但至少存在一个问题:它找不到我的类。我想这是对的:我的包驻留在我的 Web 应用程序中,而扩展加载器不在那里。还有什么好主意吗?

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

4

1 回答 1

2

直接创建一个实例jdk.nashorn.api.scripting.NashornScriptEngineFactory而不是 do engineManager.engineByName(),然后ScriptEngine通过调用NashornScriptEngineFactory.getScriptEngine(ClassLoader appLoader)并将其传递给您的应用程序级加载器来创建一个。

于 2015-07-28T16:14:51.220 回答