toucan tigre tiger stampede rodeo rhino java-8 nashorn

rhino - tigre - rodeo stampede wiki



Cambiando de Rhino a Nashorn (7)

Tengo un proyecto de Java 7 que hace mucho uso de Javascript para scripting varias características. Hasta ahora estaba usando Rhino como motor de script. Ahora me gustaría pasar a Java 8, lo que también significa que reemplazaré Rhino por Nashorn.

¿Qué tan compatible es de Nashorn a Rhino? ¿Puedo usarlo como reemplazo directo, o puedo esperar que algunos de mis scripts no funcionen más y deban ser portados al nuevo motor? ¿Existen características de uso común de Rhino que no sean compatibles con Nashorn?



Nashorn en Java8 no es compatible con AST. Por lo tanto, si tiene un código Java que inspecciona el árbol de origen JS utilizando el mecanismo AST de Rhino, es posible que tenga que volver a escribirlo (usando expresiones regulares tal vez) una vez que haya portado su código para usar Nashorn.

Estoy hablando de esta API https://mozilla.github.io/rhino/javadoc/org/mozilla/javascript/ast/AstNode.html

Nashorn en Java9 soporta AST sin embargo.


Nashorn no puede acceder a una clase interna cuando esa clase interna se declara privada, lo que Rhino pudo hacer:

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

Bajo Java8 este código lanza la siguiente excepción:

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)


Noté que Rhino no tenía un problema con una función llamada ''in ()'' (aunque ''in'' es una palabra clave reservada de JavaScript).
Nashorn sin embargo levanta un error.


Para usar el método importClass en JDK 8, necesitamos agregar el siguiente comando:

load("nashorn:mozilla_compat.js");

Sin embargo, este cambio afecta la ejecución en JDK 7 (JDK no da soporte para cargar el método).

Para mantener la compatibilidad para ambos SDK, resolví este problema agregando la cláusula try / catch:

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


Una característica que está en Rhino y no en Nashorn: exponer miembros estáticos a través de instancias.

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

Mi convicción es que la exposición de miembros estáticos a través de instancias es una combinación descuidada de espacios de nombres por lo demás separados, por lo que opté por no habilitarlo.

Creo que esto está muy mal. Mientras tengamos que usar dos construcciones diferentes para acceder al mismo objeto java y usar declaraciones de paquetes innecesariamente en javascript, el código se vuelve más difícil de leer y escribir porque la carga cognitiva aumenta. Prefiero quedarme con Rhino entonces.

No he encontrado una solución para este obvio "error de diseño" todavía.


Un problema es que Nashorn ya no puede importar por defecto paquetes enteros de Java en el ámbito global mediante el uso de importPackage(com.organization.project.package);

Sin embargo, hay una solución simple: al agregar esta línea a su script, puede habilitar el comportamiento anterior de Rhino:

load("nashorn:mozilla_compat.js");

Otro problema con el que me encontré es que ciertas conversiones de tipo al pasar datos entre java y javascript funcionan de manera diferente. Por ejemplo, el objeto que llega cuando se pasa una matriz de Javascript a Java ya no se puede convertir a la List , pero se puede convertir a un Map<String, Object> . Como solución alternativa, puede convertir la matriz de Javascript en una Lista de Java en el código de Javascript utilizando Java.to(array, Java.type("java.util.List"))