Switching from Rhino to Nashorn
Asked Answered
C

7

29

I have a Java 7 project which makes a lot of use of Javascript for scripting various features. Until now I was using Rhino as script engine. I would now like to move to Java 8, which also means that I will replace Rhino by Nashorn.

How compatible is Nashorn to Rhino? Can I use it as a drop-in replacement, or can I expect that some of my scripts will not work anymore and will need to be ported to the new engine? Are there any commonly-used features of Rhino which are not supported by Nashorn?

Chaplin answered 19/3, 2014 at 10:19 Comment(1)
No. It is a bit dangerous. I ran into this: #28153490Romeyn
C
28

One problem is that Nashorn can no longer by default import whole Java packages into the global scope by using importPackage(com.organization.project.package);

There is, however, a simple workaround: By adding this line to your script, you can enable the old behavior of Rhino:

load("nashorn:mozilla_compat.js");

Another problem I ran into is that certain type-conversions when passing data between java and javascript work differently. For example, the object which arrives when you pass a Javascript array to Java can no longer be cast to List, but it can be cast to a Map<String, Object>. As a workaround you can convert the Javascript array to a Java List in the Javascript code using Java.to(array, Java.type("java.util.List"))

Chaplin answered 19/3, 2014 at 20:33 Comment(1)
According to this article, the "use of mozilla_compat.js and importClass is discouraged". Use var scope = new JavaImporter(com.x.y) and then scope.z (where z is in the package com.x.y). The automatic conversion from a JS array to a Java List works for me.Unscrupulous
F
10

To use the importClass method on JDK 8, we need to add the following command:

load("nashorn:mozilla_compat.js");

However, this change affect the execution on JDK 7 (JDK does not gives support to load method).

To maintain the compatibility for both SDKs, I solved this problem adding try/catch clause:

try{
    load("nashorn:mozilla_compat.js");
}catch(e){
}
Fluted answered 12/8, 2015 at 20:44 Comment(0)
A
9

Nashorn can not access an inner class when that inner class is declared private, which Rhino was able to do:

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);
      }
   }
}

Under Java8 this code throws following exception:

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)
Aureole answered 9/4, 2014 at 11:7 Comment(3)
You can only access public methods. If you change to public class Inner then it will work.Mensuration
Yes, I know. But this is some kind of incompatibility. IMHOAureole
It's all about security, which Rhino lacks.Mensuration
F
4

I noticed that Rhino didn't have a problem with a function called 'in()' (although 'in' is a reserved JavaScript keyword).
Nashorn however raise an error.

Factitious answered 12/9, 2014 at 8:15 Comment(0)
S
3

Nashorn cannot call static methods on instances! Rhino did this, therefore we had to backport Rhino to Java 8 (Here's a short summary: http://andreas.haufler.info/2015/04/using-rhino-with-java-8.html)

Spanker answered 21/4, 2015 at 7:19 Comment(0)
A
0

Nashorn on Java8 does not support AST. So if you have Java code that inspects the JS source tree using Rhino's AST mechanism , you may have to rewrite it (using regex maybe) once you port your code to use Nashorn.

I am talking about this API https://mozilla.github.io/rhino/javadoc/org/mozilla/javascript/ast/AstNode.html

Nashorn on Java9 supports AST though.

Arlenaarlene answered 30/10, 2017 at 23:24 Comment(0)
O
-1

One feature that is in Rhino and not Nashorn: exposing static members through instances.

From http://nashorn-dev.openjdk.java.narkive.com/n0jtdHc9/bug-report-can-t-call-static-methods-on-a-java-class-instance : "

My conviction is that exposing static members through instances is a sloppy mashing together of otherwise separate namespaces, hence I chose not to enable it.

I think this is deeply wrong. As long as we have to use two different constructs to access the same java object and use package declarations unnecessarily in javascript, code becomes harder to read and write because cognitive load increases. I will rather stick to Rhino then.

I have not found a workaround for this obvious "design bug" yet.

Onomasiology answered 4/2, 2016 at 15:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.