Function object cannot be called with different context

Hannes Wallnöfer hannes.wallnoefer at oracle.com
Mon Jan 30 17:52:38 UTC 2017


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.Frantzius at 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.frantzius at 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
> 



More information about the nashorn-dev mailing list