J'ai un projet Java 7 qui utilise beaucoup le langage Javascript pour écrire diverses fonctionnalités dans un script. Jusqu'à présent, j'utilisais Rhino comme moteur de script. J'aimerais maintenant passer à Java 8, ce qui signifie également que je remplacerai Rhino par Nashorn.
Dans quelle mesure Nashorn to Rhino est-il compatible? Puis-je l'utiliser comme solution de remplacement ou puis-je m'attendre à ce que certains de mes scripts ne fonctionnent plus et devront être portés sur le nouveau moteur? Existe-t-il des fonctionnalités couramment utilisées de Rhino qui ne sont pas prises en charge par Nashorn?
L’un des problèmes est que Nashorn ne peut plus, par défaut, importer des packages Java entiers dans l’étendue globale à l’aide de importPackage(com.organization.project.package);
.
Il existe cependant une solution simple: en ajoutant cette ligne à votre script, vous pouvez activer l'ancien comportement de Rhino:
load("nashorn:mozilla_compat.js");
Un autre problème que j'ai rencontré est que certaines conversions de types lors de la transmission de données entre Java et javascript fonctionnent différemment. Par exemple, l'objet qui arrive lorsque vous passez un tableau Javascript à Java ne peut plus être converti en List
, mais il peut être converti en Map<String, Object>
. Pour résoudre ce problème, vous pouvez convertir le tableau Javascript en liste Java dans le code Javascript à l'aide de Java.to(array, Java.type("Java.util.List"))
.
Pour utiliser la méthode importClass sur JDK 8, nous devons ajouter la commande suivante:
load("nashorn:mozilla_compat.js");
Cependant, cette modification affecte l'exécution sur JDK 7 (JDK ne prend pas en charge la méthode de chargement).
Pour maintenir la compatibilité des deux SDK, j'ai résolu ce problème en ajoutant une clause try/catch:
try{
load("nashorn:mozilla_compat.js");
}catch(e){
}
Nashorn ne peut pas accéder à une classe interne lorsque cette classe interne est déclarée privée, ce que Rhino a été capable de faire:
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);
}
}
}
Sous Java8, ce code lève l'exception suivante:
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)
J'ai remarqué que Rhino n'avait pas de problème avec une fonction appelée 'in ()' (bien que 'in' soit un mot clé JavaScript réservé).
Nashorn génère cependant une erreur.
Nashorn ne peut pas appeler des méthodes statiques sur des instances! Rhino a fait cela, nous avons donc dû relayer Rhino vers Java 8 (voici un bref résumé: http://andreas.haufler.info/2015/04/using-rhino-with-Java-8.html )
Nashorn sur Java8 ne supporte pas AST. Donc, si vous avez du code Java qui inspecte l’arbre source JS en utilisant le mécanisme AST de Rhino, vous devrez peut-être le réécrire (en utilisant éventuellement regex) une fois que vous aurez porté votre code à utiliser Nashorn.
Je parle de cette API https://mozilla.github.io/rhino/javadoc/org/mozilla/javascript/ast/AstNode.html
Nashorn sur Java9 supporte AST cependant.