7

I'm fairly new to Nashorn and scripting on top of the JVM and wanted to know if I can get my java code and javascripts to communicate more effectively.

I'm using a 3rd party JS lib that works with JS objects, and in my java code I have the data I want to pass as a Map<String, Object> data.

Because that 3rd party JS expects to work with plain JS objects I can't pass my data as is, although the script engine allows you to access a Map as if it was a plain JS object.

The script i'm using uses 'hasOwnProperty' on the data argument and fails when invoked on an Java object.

When I tried using Object.prototype.hasOwnProperty.call(data, 'myProp') it also didn't work and always returned 'false'. The basic problem is that a Java Object is not a javascript object prototype.

what I ended up doing something like this :

Map<String, Object> data;

ObjectMapper mapper = new ObjectMapper();   
String rawJSON = mapper.writeValueAsString(data);

ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");

engine.eval('third_party_lib.js');
engine.eval('function doSomething(jsonStr) { var jsObj = JSON.parse(jsonStr); return doSomethingElse(jsObj); }');
Object value = ((Invocable) engine).invokeFunction("doSomething", rawJSON);

This works as expected, but all this JSON parsing back and forth is heavy and feels like there might be simpler, faster and more straight forward way to do it.

So, is there a better way to pass JSON between Java and Javascript or a way to create a compatible JS object in my Java code ?

I've seen this guide to template rendering using mustache.js but it's doing pretty much the same thing.

Thanks !

2
  • what exactly is it that you want to achieve with this? To add a scriptable way of invoking the features of your Java application and operate on the data model expoded within your Java application (the designed intent of Nashorn), or to mimic Node.js and invoke arbitrary Javascript code? Commented Jul 8, 2015 at 14:12
  • I'm not invoking Java functions from Javascript at all, exactly the opposite, I want my Java application to invoke a javascript function. My specific case is rendering with React.js, but I assume this is a common use case for handlebars.js \ mustache.js or any other javascript libraries using JSON objects. Commented Jul 8, 2015 at 14:45

1 Answer 1

6

Nashorn treats java.util.Map objects specially. Nashorn allows Map keys to be treated as "properties". See also https://wiki.openjdk.java.net/display/Nashorn/Nashorn+extensions#Nashornextensions-SpecialtreatmentofobjectsofspecificJavaclasses

So if your map contains "foo" as key, script can access mapObj.foo to get it's value. It does not matter the script you evaluated is third-party one. As long as the script is evaluated by Nashorn, nashorn will specially link Map property access and get the result you want. This approach avoid unnecessary JSON string conversion and parse round trip (as you yourself mentioned).

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for your answer. You're right, I can access keys like any other property, but my problem is that the Map object does not support native javascript functionality like 'hasOwnProperty' the 3rd party lib is using. I've updated the question to make my issue more clear.
Okay, I got it. In that case, it appears round trip via JSON is inevitable.
Thanks for the hint. Here is working code example: stackoverflow.com/a/43667674/603516

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.