How to load java script having class, in jvm using nashorn - javascript

Here is my simple java script test.js with class :
class Car {
constructor(name, year) {
this.name = name;
this.year = year;
}
}
myCar = new Car("Ford", 2014);
Print("done")
Here is my java code which will try to load test.js
public class Controller {
public static void main(String[] args) {
try {
NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
ScriptEngine engine = factory.getScriptEngine("--language=es6");
engine.eval(Files.newBufferedReader(Paths.get("<Path-to-test-js>/test.js"), StandardCharsets.UTF_8));
} catch (Exception _e){
System.out.println(_e);
}
}
but its throwing exception :
javax.script.ScriptException: <eval>:1:0 Expected an operand but found class
class Car {
^ in <eval> at line number 1 at column number 0
Why its throwing exception here.

I am not able to run nashorn with my scripts , i think class is not supported.
If anyone is planning to use nashorn do not use it :
I removed class from my scripts and i tested its performance , its very slow. not even to close to expected performace of my application.
Even for study purpose i will not recommend it as its getting absolute.
Nashorn, the JavaScript engine in the OpenJDK, has been deprecated in JDK 11 by JEP 335 and has recently been scheduled to be removed in a future JDK version by JEP 372.

Related

Migrate Nashorn to GraalVM

I am using Nashorn JS engine from OpenJDK 12. Nashorn seems to be deprecated. I am looking which are the available alternatives. I found GraalVM, but I am not sure if this is the best.
How can I execute a GraalVM JavaScript from Java ? Do you have any example ?
With Nashorn was using from Java:
NashornScriptEngineFactory nsef = new NashornScriptEngineFactory();
ScriptEngine engine = nsef.getScriptEngine( BasicDBObject.class.getClassLoader() );
final Bindings binding = engine.getContext().getBindings(ScriptContext.ENGINE_SCOPE);
In Nashorn I create a WrappedMongoDatabase which extends AbstractJSObject. There I add some 'virtual' methods to simulate the MongoDB Query language, which does for example getCollection('persons').find()...
Do you know a way to replace the AbstractJSObject in GraalVM?
I had a look to ProxyObject, somehow I couldn't find a way to override the call(Object thiz, Object... args) like in AbstractJSObject.
public class WrappedMongoDatabase extends AbstractJSObject {
#Override
public boolean hasMember(String name) {
return "getCollection".equals( name ) || "createCollection".equals(name)||...;
}
#Override
public Object getMember(final String name) {
if ( hasMember( name ) ){
return new AbstractJSObject() {
#Override
public Object call(Object thiz, Object... args) {
switch( name ) {
case "getCollection":
if (args.length == 1 && args[0] instanceof String) {
return getCollection((String) args[0]);
}
break;
...
}
}
}
}
}
}
GraalVM is a solid way to go. We've been using it for a while now, it runs well, and the JavaScript implementation is far better than Nashorn (or Rhino). In particular, it is ECMA2020 compliant, it supports Node requires (that's huge!), it performs much better, etc...
GraalVM is a big step forward if you're using Nashorn, but it does require some adjustments, which are covered reasonably well in the GraalVM documentation.
Follow GraalVM ScriptEngine
ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
bindings.put("polyglot.js.allowHostAccess", true);
bindings.put("polyglot.js.allowHostClassLookup", (Predicate<String>) s -> true);
bindings.put("javaObj", new Object());
engine.eval("(javaObj instanceof Java.type('java.lang.Object'));"); // would not work without allowHostAccess and allowHostClassLookup
Notice nashorn compatibility mode:
These options control the sandboxing rules applied to evaluated JavaScript code and are set to false by default, unless the application was started in Nashorn compatibility mode (--js.nashorn-compat=true).

What is the use of overriding hasMember() inside JSObject, AbstractJSObject?

I understand that this helper method can be called from a Java code to check if your Java/JS Object has a property you are looking for
but i would like to know if this is called by the Nashorn Engine while we use this JSObject/AbstractJSObject implementation in a JavaScript code.
I am aware of the fact that doing a . inside JavaScript will in turn invoke the Java method .getMember()
If "in" operator in used in JavaScript (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/in) on a JSObject instance, Nashorn will call hasMember method on that JSObject.
Example code:
import javax.script.*;
import jdk.nashorn.api.scripting.*;
public class Main {
public static void main(String[] args) throws Exception {
ScriptEngineManager m = new ScriptEngineManager();
ScriptEngine e = m.getEngineByName("nashorn");
e.put("obj", new AbstractJSObject() {
#Override
public boolean hasMember(String name) {
System.out.println("hasMember called for " + name);
return false;
}
});
// in operator triggers hasMember call on JSObject instance
e.eval("if ('foo' in obj) print('yes')");
}
}
The output from the above program looks like:
hasMember called for foo

EntryPointNotFoundException external JS Lib error

Trying to implement JS library with my C# code.
Is very simple but I am getting this error:
EntryPointNotFoundException: Test
TalkDB.Start () (at Assets/Scripts/TalkDB.cs:30)
C# code is in scripts folder and JS library at plugins/webgl with .jslib extension.
Also read this article, but no idea what I am missing: https://docs.unity3d.com/Manual/webgl-interactingwithbrowserscripting.html?_ga=1.27144893.1658401563.1487328483
C# Code:
public class TalkDB : MonoBehaviour
{
[DllImport("__Internal")]
private static extern void Test();
void Start()
{
Test();
}
}
JS Library:
var HighscorePlugin = {
Test: function()
{
window.alert("Testing 1, 2, 3,...");
}
};
mergeInto(LibraryManager.library, HighscorePlugin);
Found the answer, is quite simple in fact.
I does not work when running locally, just when running from a server.
To prevent this error this should be done:
#if UNITY_WEBGL && !UNITY_EDITOR
[DllImport("__Internal")]
private static extern void Test();
#else
// something else to emulate what you want to do
#endif
And do this also when calling the function.
Happy programming :)
EntryPointNotFoundExceptionmeans means that the function "Test" is either (A) not marked as exportable (not visible) or (B) signature does not match C# definition.
Most likely your issue is the former (A).
I would recommend running DUMPBIN.EXE against your library to verify your "test" function is getting exported and that the its respective signature matches your C# definition. Could be some code-injection on JS-side.

Rhino JSON.stringify not definied

I'm trying to print a simple JSON from my javascript using Rhino 1.7.7.1 from maven.
public static void main(String[] args) throws JsonProcessingException {
Context context = Context.enter();
try {
ScriptableObject scope = context.initStandardObjects();
System.out.println(context.evaluateString(scope, "JSON.stringify({a:1})", null, 1, null));
} finally {
Context.exit();
}
}
But I'm got:
Exception in thread "main" org.mozilla.javascript.EcmaError: ReferenceError: "JSON" is not defined. (unnamed script#1)
at org.mozilla.javascript.ScriptRuntime.constructError(ScriptRuntime.java:3654)
at org.mozilla.javascript.ScriptRuntime.constructError(ScriptRuntime.java:3632)
at org.mozilla.javascript.ScriptRuntime.notFoundError(ScriptRuntime.java:3717)
at org.mozilla.javascript.ScriptRuntime.name(ScriptRuntime.java:1692)
at org.mozilla.javascript.gen.c1._c0(unnamed script:1)
at org.mozilla.javascript.gen.c1.call(unnamed script)
at org.mozilla.javascript.ContextFactory.doTopCall(ContextFactory.java:398)
at org.mozilla.javascript.ScriptRuntime.doTopCall(ScriptRuntime.java:3065)
at org.mozilla.javascript.gen.c1.call(unnamed script)
at org.mozilla.javascript.gen.c1.exec(unnamed script)
at org.mozilla.javascript.Context.evaluateString(Context.java:1104)
at mypackage.RhinoService.main(RhinoService.java:34)
JSON.stringify is not implemented in the Rhino 1.7 engine. See the Rhino compatibility table.

Pass object from Javascript to C++/CX based on C++/CX interface - Windows Runtime Components

I'm new to Windows Runtime Component, and have been trying to figure out how to achieve the following.
The C++ interface I want to extend from in Javascript.
namespace MySDK {
public interface class LoggerPlugin
{
public:
virtual void Log (Platform::String^ Tag, Platform::String^ Messsage);
};
}
The C++
namespace MySDK {
public ref class Logger sealed : public Platform::Object
{
public:
static Logger^ GetInstance ();
void SetPlugin (LoggerPlugin^ Plugin);
};
}
What I tried, may seem silly, but I have no idea how to achieve it.
var plugin = {
log: function(tag, message) {
console.log(tag + ':' + message);
}
};
MySdk.Logger.getInstance().setPlugin(plugin);
The error that I get is
JavaScript runtime error: Type mismatch
I couldn't find any documentation or examples on how to achieve this, will appreciate if anyone could provide me an example of how this can be done.
JavaScript cannot implement WinRT interfaces. If you want to have a JavaScript implementation of your plugin, then you will need to build a concrete type that raises events (that JavaScript can subscribe to) rather than defining virtual methods (that C++ or C# could implement).

Categories

Resources