从Rhino切换到Nashorn

时间:2014-03-19 10:19:02

标签: rhino java-8 nashorn

我有一个Java 7项目,该项目大量使用Javascript来编写各种功能的脚本。到目前为止,我使用Rhino作为脚本引擎。我现在想转向Java 8,这也意味着我将用Nashorn取代Rhino。

Nashorn与Rhino的兼容性如何?我是否可以将其用作替代品,或者我是否可以预期我的某些脚本将不再工作并且需要移植到新引擎?是否有Nashorn不支持的Rhino常用功能?

7 个答案:

答案 0 :(得分:25)

一个问题是Nashorn不能再默认使用importPackage(com.organization.project.package);

将整个Java包导入全局范围

然而,有一个简单的解决方法:通过在脚本中添加此行,您可以启用Rhino的旧行为:

load("nashorn:mozilla_compat.js");

我遇到的另一个问题是,在java和javascript之间传递数据时,某些类型转换的工作方式不同。例如,将Javascript数组传递给Java时到达的对象不能再转换为List,但可以强制转换为Map<String, Object>。作为一种解决方法,您可以使用Java.to(array, Java.type("java.util.List"))将Javascript数组转换为Javascript代码中的Java列表

答案 1 :(得分:10)

要在JDK 8上使用 importClass 方法,我们需要添加以下命令:

load("nashorn:mozilla_compat.js");

但是,此更改会影响JDK 7上的执行(JDK不支持加载方法)。

为了保持两个SDK的兼容性,我解决了添加try / catch子句的问题:

try{
    load("nashorn:mozilla_compat.js");
}catch(e){
}

答案 2 :(得分:9)

当内部类被声明为私有时,Nashorn无法访问内部类,Rhino能够做到:

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class Test {
   public static void main(String[] args) {
     Test test = new Test();
     test.run();
   }

   public void run() {
      ScriptEngineManager factory = new ScriptEngineManager();
      ScriptEngine engine = factory.getEngineByName("JavaScript");

      Inner inner = new Inner();
      engine.put("inner", inner);

      try {
         engine.eval("function run(inner){inner.foo(\"test\");} run(inner);");
      } catch (ScriptException e) {
         e.printStackTrace();
      }
   }

   private class Inner {
      public void foo(String msg) {
         System.out.println(msg);
      }
   }
}

在Java8下,此代码抛出以下异常:

javax.script.ScriptException: TypeError: kz.test.Test$Inner@117cd4b has no such function "foo" in <eval> at line number 1
    at jdk.nashorn.api.scripting.NashornScriptEngine.throwAsScriptException(NashornScriptEngine.java:564)
    at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:548)

答案 3 :(得分:4)

我注意到Rhino没有遇到名为'in()'的函数的问题(尽管'in'是一个保留的JavaScript关键字)。
Nashorn会引发错误。

答案 4 :(得分:3)

Nashorn无法在实例上调用静态方法! Rhino做到了这一点,因此我们不得不将Rhino移植到Java 8(这里是一个简短的摘要:http://andreas.haufler.info/2015/04/using-rhino-with-java-8.html

答案 5 :(得分:0)

Java8上的Nashorn不支持AST。因此,如果你有使用Rhino的AST机制检查JS源代码树的Java代码,一旦你移植代码使用Nashorn,你可能不得不重写它(使用正则表达式)。

我说的是这个API https://mozilla.github.io/rhino/javadoc/org/mozilla/javascript/ast/AstNode.html

Java9上的Nashorn支持AST。

答案 6 :(得分:-1)

Rhino中的一个功能而非Nashorn:通过实例公开静态成员。

来自http://nashorn-dev.openjdk.java.narkive.com/n0jtdHc9/bug-report-can-t-call-static-methods-on-a-java-class-instance:&#34;

  

我的信念是,通过实例公开静态成员是一个   笨拙的混合在一起的其他单独的命名空间,因此我   选择不启用它。

我认为这是非常错误的。只要我们必须使用两个不同的构造来访问相同的java对象并在javascript中不必要地使用包声明,代码就会变得更难以读写,因为认知负载会增加。我宁愿坚持使用Rhino。

我还没有为这个明显的设计错误找到解决方法&#34;爱好。