2017-02-20 36 views
2

我用下面的代碼與Rhino JavaScript引擎中的Java:訪問可變

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

腳本的輸出(使用Rhino)是:

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

Nashorn JavaScript引擎,我得到了result沒有價值:

​​3210 個

回報

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

如何訪問使用nashorn發動機ScriptContextresult變量的值?

回答

2

如果使用ScriptEngine.createEngine API來創建ENGINE_SCOPE綁定,它會按預期工作:

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()'返回無論是'新SimpleBindings()',如果全球每引擎設置,或'createGlobalMirror()'如果沒有設置。 '創建發動機之前;全球每engine',或添加行'System.setProperty(「nashorn.args」,「--global每次發動機」) - 與任一'-Dnashorn.args =運行,都會導致'ctx.getAttribute(「result」)'再次返回'null'。解決Nashorn的全球問題是將Nashorn嵌入到Java應用程序中的最大難題之一。 – AJNeufeld

1

Nashorn將存儲在ScriptContext中的Bindings視爲「只讀」。 任何試圖設置存儲在Bindings對象的變量(或創建一個新的變量)將導致nashorn.global創建了一個新的變量被其陰影由該名稱的Bindings參數。

您可以使用引擎「評估」的變量,使用此代碼:

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

這一點,但是,相當難看。首先將「結果」編譯成腳本,然後對該腳本進行評估,以返回變量的值。對於測試來說很好,但對於一般解決方案來說可能有點太低效。

更好,但也許更脆弱的方法,是提取「nashorn.global」可變的,並且查詢它爲所需的值。

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

又見Capturing Nashorn's Global Variables我的黑客/答案評估腳本後,移動nashorn.global值回Map<String,Object>的自動化的方法。

+0

有可能創建一個使用ScriptEngine.createBindings API一個新的綁定對象。這創建了一個直接由Nashorn的Global實例支持的綁定 - 它始終將讀/寫反映到JS全局範圍中。 –

+0

@ A.Sundararajan如果'-Dnashorn.args = - 全球每engine'設置,那麼這個問題即使你使用'ScriptEngine.createBindings保持()'。 – AJNeufeld

+0

對於每引擎 - 全局變量,每個引擎只有一個底層JS/Nashorn全局對象。所有ENGINE_SCOPE綁定將共享相同的底層Nashorn全局實例!正如您所觀察到以上,engine.createBindings()在--global-每個引擎的情況下將只返回一個SimpleBindings(用新的犀牛全球實例支持不綁定)。 –