Reputation: 2224
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
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