java


Java code cannot invoke method from scriptengine with new context


I am trying to implement example invoking method from Javascript in Java.
private static final String JS = "function doit(p) { list.add(p); return true; }";
public static void main(String[] args) throws ScriptException, NoSuchMethodException {
List<String> list = new ArrayList<>();
ScriptEngineManager scriptManager = new ScriptEngineManager();
ScriptEngine engine = scriptManager.getEngineByName("nashorn");
ScriptContext context = new SimpleScriptContext();
context.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE);
Bindings scope = context.getBindings(ScriptContext.ENGINE_SCOPE);
scope.put("list", list);
engine.eval(JS, context);
Invocable invocable = (Invocable) engine;
invocable.invokeFunction("doit", "Hello!!!");
System.out.println(list.size());
}
}
This code throws exception:
Exception in thread "main" java.lang.NoSuchMethodException: No such function doit
at jdk.nashorn.api.scripting.ScriptObjectMirror.callMember(ScriptObjectMirror.java:204)
at jdk.nashorn.api.scripting.NashornScriptEngine.invokeImpl(NashornScriptEngine.java:383)
at jdk.nashorn.api.scripting.NashornScriptEngine.invokeFunction(NashornScriptEngine.java:190)
at testjavascriptinteraction.TestJavaScript.main(TestJavaScript.java:32)
Version
java -version
openjdk version "1.8.0_91"
OpenJDK Runtime Environment (build 1.8.0_91-8u91-b14-3ubuntu1~16.04.1-b14)
OpenJDK 64-Bit Server VM (build 25.91-b14, mixed mode)
What is wrong?
I can reproduce this problem, and have found a way how to solve it.
I had a hunch that after casting to Invocable, the engines own scripting context is still being used, and not the temporary one you have passed to eval.
I can fix this by calling engine.setContext(...) with this context before casting to Invacable. i.e.:
...
scope.put("list", list);
engine.eval(JS, context); // 'context' now contains the 'doit' function.
engine.setContext(context); // <-- Right here
Invocable invocable = (Invocable) engine; // Now the Invocable will use 'context'.
invocable.invokeFunction("doit", "Hello!!!"); //Runs fine
System.out.println(list.size());
The fact that this works seems to confirm my hunch.
Your scope and your eval() are both using a custom ScriptContext, but your invokeFunction() is not. The function is registered with the context, not the engine.
Option 1: Don't use a custom context.
List<String> list = new ArrayList<>();
ScriptEngineManager scriptManager = new ScriptEngineManager();
ScriptEngine engine = scriptManager.getEngineByName("nashorn");
Bindings scope = engine.getBindings(ScriptContext.ENGINE_SCOPE);
scope.put("list", list);
engine.eval("function doit(p) { list.add(p); return true; }");
Invocable invocable = (Invocable) engine;
invocable.invokeFunction("doit", "Hello!!!");
System.out.println(list); // prints: [Hello!!!]
UPDATE
Option 2: Call registered function directly.
A function get registered with the context as a normal variable with a function value. This means that your scope will have a doit variable after the eval() call.
You will have to use a Nashorn class to call it directly, but it's easy.
// same code as above up to eval call
engine.eval("function doit(p) { list.add(p); return true; }", context);
// Instead of invokeFunction(), just get and call function manually
JSObject func = (JSObject)scope.get("doit");
func.call(null, "Hello!!!"); // like a "static" call, no 'this' value
System.out.println(list); // prints: [Hello!!!]

Related Links

How to remove a view added using addContentView?
Remove unnecessary decimals
How enable scroll using scroll composite in gridlayout?
Youtube Video id by using Service account - got error 403 response
Defining AudioFormat in Java on Ubuntu
Where is the method getDriver initialized in java.sql.DriverManager in JAVA?
Issues with Android Studio 1.0.2
How to return Calendar object in Custom Date format
Color picker not in activity [closed]
Error creating table using Hibernate Schema Updater
Tray Icon displayed not properly
“out.println” not working in jsp
Delete specific HTML tags in String
How to mock method parameter in Mockito
Table not found error in h2 using hibernate3
Access Report from p:menuitem

Categories

HOME
vim
client
activiti
angular-material
lodash
bookshelf.js
cmd
sqlite3
binary-tree
icloud
ojdbc
node-pdfkit
wheelnav.js
windows-azure-storage
visual-studio-2005
vaadin7
seaborn
aurigma
swingx
ml
xlsxwriter
functional-testing
smb
cas
react-css-modules
brunch
bootstrap-material-design
large-file-upload
objectanimator
fabric8
contact-form
vsts-build-task
http-digest
io-redirection
multilingual
streamsets
leading-zero
broadcastreceiver
email-templates
g-code
node-gyp
android-mediaprojection
.net-4.6.2
eclipse-gef
wptoolkit
cubic-spline
azure-application-gateway
paxos
datastax-startup
r-forge
dynamics-sl
wdf
dstu2-fhir
thrust
autorest
testng-dataprovider
livequery
design-by-contract
system.management
freelancer.com-api
xna-4.0
r-tree
intel-fortran
sdhc
eclipse-clp
atk4
computer-algebra-systems
muse
ios9.1
appfabric-cache
clipperlib
jsapi
umbraco6
directoryservices
gui-test-framework
android-nested-fragment
preferences
code-access-security
bitcoinj
terminfo
ceil
android-radiobutton
tld
mechanize-ruby
didselectrowatindexpath
balanced-payments
xsockets.net
soundtouch
back-stack
drools-planner
browser-detection
viewswitcher
buildr
php-parser
doh
iphone-web-app
xfbml
modelstate
nsviewanimation
perfect-hash
web-architecture
zend-tool
mtj
uimenucontroller
zend-decorators

Resources

Mobile Apps Dev
Database Users
javascript
java
csharp
php
android
MS Developer
developer works
python
ios
c
html
jquery
RDBMS discuss
Cloud Virtualization
Database Dev&Adm
javascript
java
csharp
php
python
android
jquery
ruby
ios
html
Mobile App
Mobile App
Mobile App