There are a few problems with this code. The first is that a function 
declaration evaluates as undefined in Javascript, so your jsFunction variable 
is null. One way to work around this is to make the function an expression, 
e.g. by wrapping it in parentheses:

engine.eval(„function test() { }“);  // returns null but defines function „test"
engine.eval(„(function test() { })“);  // returns the function but doesn’t 
define it in scope

Another issue is that Nashorn cannot directly use the default Binding 
implementation used by SimpleScriptContext. You should create a native Nashorn 
global object using engine.createBindings() as described in 
http://docs.oracle.com/javase/8/docs/technotes/guides/scripting/prog_guide/api.html

        ScriptContext newContext = new SimpleScriptContext();
        newContext.setBindings(engine.createBindings(), 
ScriptContext.ENGINE_SCOPE);
        Bindings engineScope = 
newContext.getBindings(ScriptContext.ENGINE_SCOPE);

However, even with these issues fixed the problem remains that JavaScript 
functions are closures over the scope they were evaluated in. An evaluated 
function is always bound to the global object it was evaluated in. You can use 
the Compilable interface (as you did in your code) to create a compiled version 
of a script that will run with multiple globals:

    ScriptEngine engine =  new 
ScriptEngineManager().getEngineByName("JavaScript");
    CompiledScript compiledScript = ((Compilable) engine).compile("function 
test() {return foo;}; test();“);
    
    ScriptContext context = new SimpleScriptContext();
    context.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE);
    context.setAttribute("foo", "bar", ScriptContext.ENGINE_SCOPE);
    Object result = compiledScript.eval(context);

Hannes


> Am 30.01.2017 um 11:28 schrieb Frantzius, Jörg <joerg.frantz...@aperto.com>:
> 
> Hi,
> 
> in my code, I get hold of a function object from some 3rd party Javascript 
> code, and I need to execute that function within a new context, i.e. make new 
> ENGINE_SCOPE bindings available to it. ScriptObjectMirror.call() 
> unfortunately does not allow to define a context to execute in, so I tried to 
> workaround by calling the function from a CompiledScript that in turn can be 
> executed with a custom context:
> 
>    @Test
>    public void testJsFunctionWithContext() throws ScriptException {
>        ScriptEngine engine =  new 
> ScriptEngineManager().getEngineByName("JavaScript");
>        jdk.nashorn.api.scripting.ScriptObjectMirror jsFunction = 
> (ScriptObjectMirror) engine.eval("function test() {return foo;}");
> 
>        ScriptContext context = new SimpleScriptContext();
>        context.setAttribute("foo", "bar", ScriptContext.ENGINE_SCOPE);
>        context.setAttribute("fn", jsFunction, ScriptContext.ENGINE_SCOPE);
> 
>        // does work: access context directly
>        CompiledScript contextWrapper = ((Compilable) engine).compile("foo");
>        String result = (String) contextWrapper.eval(context);
>        assertEquals("bar", result);
> 
>        // does not work: access context from within function ("foo" is not 
> defined)
>        contextWrapper = ((Compilable) engine).compile("fn()");
>        result = (String) contextWrapper.eval(context);
>        assertEquals("bar", result);
>    }
> 
> Is there some mistake I made here, or is it simply not possible for a 
> function object to access variables from a new context?
> If that’s really not possible, is there maybe a way of turning a function 
> object into a CompiledScript object, which can then be evaluated with a new 
> context?
> 
> Thanks for any help,
> Jörg
> 
> 
> 
> ---
> 
> Dipl. Inf. Jörg von Frantzius, Technical Director
> 
> E-Mail joerg.frantz...@aperto.com
> 
> Phone +49 30 283921-318
> Fax +49 30 283921-29
> 
> Aperto GmbH – An IBM Company
> Chausseestraße 5, D-10115 Berlin
> http://www.aperto.com<http://www.aperto.de/>
> http://www.facebook.com/aperto
> https://www.xing.com/companies/apertoag
> 
> HRB 77049 B, AG Berlin Charlottenburg
> Geschäftsführer: Dirk Buddensiek, Kai Großmann, Stephan Haagen, Daniel Simon
> 

Reply via email to