2017-02-20 1 views
2

J'ai utilisé le code suivant avec le moteur JavaScript Rhino en Java:variable d'accès de scriptContext à l'aide Nashorn JavaScript Engine (Java 8)

@Test 
public void testRhino() throws ScriptException { 
    final ScriptEngineManager factory = new ScriptEngineManager(); 
    final ScriptEngine engine = factory.getEngineByName("rhino"); 
    final String raw = "I am the raw value injected"; 
    final ScriptContext ctx = new SimpleScriptContext(); 
    ctx.setAttribute("raw", raw, ScriptContext.ENGINE_SCOPE); 

    String script = "var result = 'I am a result';"; 
    script += "java.lang.System.out.println(raw);"; 
    script += "'I am a returned value';"; 

    final Object res = engine.eval(script, ctx); 
    System.out.println(ctx.getAttribute("result")); 
    System.out.println(res); 
} 

La sortie du script (en utilisant Rhino) est:

I am the raw value injected 
I am a result 
I am a returned value 

dans le moteur JavaScript Nashorn, je reçois pas de valeur pour le result:

@Test 
public void testNashorn() throws ScriptException { 
    final ScriptEngineManager factory = new ScriptEngineManager(); 
    final ScriptEngine engine = factory.getEngineByName("nashorn"); 
    final String raw = "I am the raw value injected"; 
    final ScriptContext ctx = new SimpleScriptContext(); 
    ctx.setAttribute("raw", raw, ScriptContext.ENGINE_SCOPE); 

    String script = "var result = 'I am a result';"; 
    script += "java.lang.System.out.println(raw);"; 
    script += "'I am a returned value';"; 

    final Object res = engine.eval(script, ctx); 
    System.out.println(ctx.getAttribute("result")); 
    System.out.println(res); 
} 

retours

I am the raw value injected 
null 
I am a returned value 

Comment puis-je accéder à la valeur de la variable result du ScriptContext en utilisant le moteur nashorn?

Répondre

2

Si vous utilisez ScriptEngine.createEngine API pour créer ENGINE_SCOPE Manchettes, cela fonctionnera comme prévu:

import javax.script.*; 

public class Main { 
    public static void main(String[] args) throws Exception { 

    final ScriptEngineManager factory = new ScriptEngineManager(); 
    final ScriptEngine engine = factory.getEngineByName("nashorn"); 
    final String raw = "I am the raw value injected"; 
    final ScriptContext ctx = new SimpleScriptContext(); 

    // **This is the inserted line** 
    ctx.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE); 

    ctx.setAttribute("raw", raw, ScriptContext.ENGINE_SCOPE); 

    String script = "var result = 'I am a result';"; 
    script += "java.lang.System.out.println(raw);"; 
    script += "'I am a returned value';"; 

    final Object res = engine.eval(script, ctx); 
    System.out.println(ctx.getAttribute("result")); 
    System.out.println(res); 
} 
} 
+0

'NashornScriptEngine # createBindings()' renvoie soit 'new SimpleBindings()', si global-per-engine est défini, soit 'createGlobalMirror()' s'il n'est pas défini. Exécution avec '-Dnashorn.args = - global-per-engine', ou en ajoutant la ligne' System.setProperty ("nashorn.args", "--global-per-engine"); 'avant la création du moteur , provoquera 'ctx.getAttribute (" result ")' pour retourner 'null'. Travailler autour du global de Nashorn est l'une des plus grandes difficultés dans l'intégration de Nashorn dans une application Java. – AJNeufeld

1

Nashorn traite le Bindings stocké dans ScriptContext en "lecture seule". Toute tentative de définition d'une variable stockée dans un objet Bindings (ou pour créer une nouvelle variable) entraîne la création d'une nouvelle variable dans nashorn.global qui masque le paramètre Bindings par ce nom.

Vous pouvez utiliser le moteur pour "évaluer" la variable, en utilisant ce code:

System.out.println(engine.eval("result", ctx)); 

C'est cependant tout à fait laid. "result" est d'abord compilé dans un script, puis ce script est évalué, pour retourner la valeur de la variable. Bien pour tester, mais peut-être un peu trop inefficace pour une solution générale.

Une meilleure méthode, mais peut-être plus fragile, consiste à extraire la variable "nashorn.global" et à l'interroger pour obtenir la valeur désirée.

Bindings nashorn_global = (Bindings) ctx.getAttribute("nashorn.global"); 
System.out.println(nashorn_global.get("result")); 

Voir aussi mon bidouille/réponse Capturing Nashorn's Global Variables pour manière automatisée de déplacement nashorn.global valeurs à un Map<String,Object> après l'évaluation d'un script.

+0

Il est possible de créer un nouveau Manchettes objet à l'aide API ScriptEngine.createBindings. Cela crée une liaison qui est directement soutenue par l'instance globale de Nashorn - qui reflète toujours les lectures/écritures dans la portée globale de JS. –

+0

@ A.Sundararajan Si '-Dnashorn.args = - global-per-engine' est défini, alors le problème persiste même si vous utilisez' ScriptEngine.createBindings() '. – AJNeufeld

+0

Avec --globals-per-engine, il n'y a qu'un seul objet global JS/Nashorn sous-jacent par moteur. Toutes les liaisons ENGINE_SCOPE partageront la même instance globale Nashorn sous-jacente! Comme vous l'avez noté ci-dessus, engine.createBindings() dans le cas --global-per-engine retournera juste un SimpleBindings (pas un bindings soutenu par une nouvelle instance Nashorn Global). –