Ned Twigg
Ned Twigg

Reputation: 2224

Set a javascript name to be a Java function in Nashorn

I'd like to make a function available to Nashorn, something like this:

public class StackOverflow {
    private Object toSave;

    @Test
    public void test() {
        ScriptEngine jsEngine = new ScriptEngineManager().getEngineByName("nashorn");
        ScriptContext context = jsEngine.getContext();
        context.setAttribute("saveValue", arg -> { toSave = arg; }, ScriptContext.ENGINE_SCOPE);
        jsEngine.eval("saveValue('one')");
        Assert.assertEquals("one", toSave);
    }
}

The code above doesn't compile because ScriptContext.setAttribute() requires an Object, and lambdas aren't Objects. How can I set a javascript name to be a java function?

Edit for clarification:

In JavaScript, we can write this:

var square = function(y) {
   return y * y;
};
square(9);

If I have written square in Java, how can I assign that function to a JavaScript variable?

Upvotes: 2

Views: 782

Answers (1)

Ned Twigg
Ned Twigg

Reputation: 2224

Thanks to @Seelenvirtuose, turns out that you can just set it to a Consumer (or any other functional interface) and then Nashorn will do the right thing. The test below passes.

public class StackOverflow {
    private Object toSave;

    @Test
    public void test() throws ScriptException {
        Consumer<String> saveValue = obj -> toSave = obj;
        ScriptEngine jsEngine = new ScriptEngineManager().getEngineByName("nashorn");
        ScriptContext context = jsEngine.getContext();
        context.setAttribute("saveValue", saveValue, ScriptContext.ENGINE_SCOPE);
        jsEngine.eval("saveValue('one')");
        Assert.assertEquals("one", toSave);
    }
}

EDIT: I put together a teensy little zero-dependency library for passing lambdas to a script: JScriptBox. Helped me, maybe it'll help you.

private int square(int x) {
    return x * x;
}

@Test
public void example() throws ScriptException {
    TypedScriptEngine engine = JScriptBox.create()
        .set("square").toFunc1(this::square)
        .set("x").toValue(9)
        .buildTyped(Nashorn.language());
    int squareOfX = engine.eval("square(x)", Integer.class);
    Assert.assertEquals(81, squareOfX);
}

Upvotes: 2

Related Questions