I have two js files,
one is js library
second one is a simple script usually somewhat around 50 lines, that needs to access functions from the library.
In my project im trying to precompile all javascripts during my application startup, and then at runtime only invoke CompiledScripts with desired parameters.
I ended up with the following code
static String LIBRARY = "function hello(arg) {return 'Hello ' + arg;};";
static String SCRIPT = "hello(arg)";
public static void main(String... args) throws Exception {
ScriptEngine engine = new ScriptEngineManager().getEngineByName("Nashorn");
Compilable compilable = ((Compilable) engine);
CompiledScript compiledLib = compilable.compile(LIBRARY);
compiledLib.eval();
CompiledScript actualScript = compilable.compile(SCRIPT);
Bindings helloParams = new SimpleBindings();
helloParams.put("arg","world");
ScriptObjectMirror result = (ScriptObjectMirror) actualScript.eval(helloParams);
System.out.println(result);
}
But this code throws an error
> compiledScript.eval(helloParams);
<eval>:1 ReferenceError: "hello" is not defined
How can i access context of "compiledLib" (ie methods and variables) from within the "actualScript"?
Compiling doesn't register the hello() function, it just parses the JavaScript code.
You need to execute the code for the function to be registered.
Remember, in JavaScript, there is very little difference between these two statements, except that function declarations are hoisted and can therefore be used before the declaration statement:
function hello(arg) {return 'Hello ' + arg;};
var hello = function(arg) {return 'Hello ' + arg;};
There is therefore little reason to separately compile the LIBRARY code, you just run it and save off all the created global variables, which are the library methods. E.g. after executing your LIBRARY code, you'll have a global variable named hello.
ScriptEngine engine = new ScriptEngineManager().getEngineByName("Nashorn");
Compilable compilable = ((Compilable) engine);
// Process LIBRARY code
Bindings bindings = new SimpleBindings();
engine.eval(LIBRARY, bindings);
// Compile SCRIPT code
CompiledScript actualScript = compilable.compile(SCRIPT);
// Run SCRIPT code
bindings.put("foo", "world");
Object result = actualScript.eval(bindings);
System.out.println(result);
Output
Hello world
Related
tl;dr:
How do/can I store the function-handles of multiple js-functions in java for using them later? Currently I have two ideas:
Create multipe ScriptEngine instances, each containing one loaded function. Store them in a map by column, multiple entries per column in a list. Looks like a big overhead depending on how 'heavy' a ScriptEngine instance is...
Some Javascript solution to append methods of the same target field to an array. Dont know yet how to access that from the java-side, but also dont like it. Would like to keep the script files as stupid as possible.
var test1 = test1 || [];
test1.push(function(input) { return ""; });
???
Ideas or suggestions?
Tell me more:
I have a project where I have a directory containing script files (javascript, expecting more than hundred files, will grow in future). Those script files are named like: test1;toupper.js, test1;trim.js and test2;capitalize.js. The name before the semicolon is the column/field that the script will be process and the part after the semicolon is a human readable description what the file does (simplified example). So in this example there are two scripts that will be assigned to the "test1" column and one script to the "test2" column. The js-function template basically looks like:
function process(input) { return ""; };
My idea is, to load (and evaluate/compile) all script files at server-startup and then use the loaded functions by column when they are needed. So far, so good.
I can load/evaluate a single function with the following code. Example uses GraalVM, but should be reproducable with other languages too.
final ScriptEngine engine = new ScriptEngineManager().getEngineByName("graal.js");
final Invocable invocable = (Invocable) engine;
engine.eval("function process(arg) { return arg.toUpperCase(); };");
var rr0 = invocable.invokeFunction("process", "abc123xyz"); // rr0 = ABC123XYZ
But when I load/evaluate the next function with the same name, the previous one will be overwritten - logically, since its the same function name.
engine.eval("function process(arg) { return arg + 'test'; };");
var rr1 = invocable.invokeFunction("process", "abc123xyz"); // rr1 = abc123xyztest
This is how I would do it.
The recommended way to use Graal.js is via the polyglot API: https://www.graalvm.org/reference-manual/embed-languages/
Not the same probably would work with the ScriptEngine API, but here's the example using the polyglot API.
Wrap the function definition in ()
return the functions to Java
Not pictured, but you probably build a map from the column name to a list of functions to invoke on it.
Call the functions on the data.
import org.graalvm.polyglot.*;
import org.graalvm.polyglot.proxy.*;
public class HelloPolyglot {
public static void main(String[] args) {
System.out.println("Hello Java!");
try (Context context = Context.create()) {
Value toUpperCase = context.eval("js", "(function process(arg) { return arg.toUpperCase(); })");
Value concatTest = context.eval("js", "(function process(arg) { return arg + 'test'; })");
String text = "HelloWorld";
text = toUpperCase.execute(text).asString();
text = concatTest.execute(text).asString();
System.out.println(text);
}
}
}
Now, Value.execute() returns a Value, which I for simplicity coerce to a Java String with asString(), but you don't have to do that and you can operate on Value (here's the API for Value: https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Value.html).
I have written a project that calculates different functions like sine,MCM etc without using existing packages like math in java
now I want to get an expression from the user in form of a string and then print out the result
like :
import java.util.Scanner;
public class Phase2main {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
String expression ;
double result = 0 ;
System.out.println(" Enter your desired expression from the available functions ");
expression = s.nextLine();
System.out.println("Result is : " + result);
}
}
then it should run like this:
Enter an Expression: ADD(DIV(SIN(FACT(3)),CEIL(TAN(MUL(1.5,FIB(4))))),GCD(2,10))
The Result is: 1.94
how can I make the program to identify my functions like CEIL and their input ?
I've checked many of the similar questions but the ones that I found are rather libraries that are too complex for me to understand or do basic arithmetic without identifying functions and their inputs
so how can I write a simple evaluator for this specific problem?
May be use JavaScript interpreter?
First create engine instance and init:
// Manager creates engines by mime/language names.
// It has own global scope for engiges created by it.
ScriptEngineManager manager = new ScriptEngineManager();
// Create JavaScript interpreter instance.
// (Nashorn is bundled JavaScript interpreter)
ScriptEngine scope = manager.getEngineByName("JavaScript");
// Define functions you need
String initialScript = "cos = Math.cos;" // ; or \n
+ "sin = Math.sin;"
+ "tg = Math.tan;"
+ "PI = Math.PI;"
// Any other function
+ "ctg = function (x) { return cos(x)/sin(x); };";
// ...
try {
// Add these functions to scope
scope.eval(initialScript);
} catch(ScriptException ex) {
// Evaluating exceptions, syntax errors are thrown here
}
And then you can evaluate expressions in the "scope" many times:
try {
double d = (double)scope.eval("sin(PI/2) + cos(PI/2)");
System.out.println("Calculated: " + d);
} catch(ScriptException e) {
// ...
}
Be warned:
There is language interpreting - user can pass any script and...
... it can reduce perfomance of application.
You can also use, for example, Jython or JRuby as interpreter.
You could use the Java Scripting API, and for instance use JavaScript, or BeanShell (java like).
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByMimeType("text/javascript");
try {
engine.eval("print('Result: ' + java.lang.Math.sin(0.8))");
double y = ((Number) engine.eval("java.lang.Math.sin(0.8)")).doubleValue();
} catch (ScriptException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
JavaScript can use imports. As you can see, calling java is quite simple.
I'm not sure if there is any simple way to identify and evaluate generic inputed expressions without using libraries.
If you want to develop your own way to evaluate math expressions take a look on this page, it should show you the way to go: http://cogitolearning.co.uk/?p=565
And if you change your mind and want to use an library, check this link: Evaluating a math expression given in string form
I've done this when I built a java compiler, that way I could read and evaluate any expression, but it wasn't simple...
I want to retrieve object generated in JS store them in Java and later call methods on them.
This worked with Java 7, now with Java 8 i get an exception:
Exception in thread "main" java.lang.IllegalArgumentException: no current Global instance for nashorn
at jdk.nashorn.api.scripting.NashornScriptEngine.invokeImpl(NashornScriptEngine.java:492)
at jdk.nashorn.api.scripting.NashornScriptEngine.invokeMethod(NashornScriptEngine.java:238)
I have modified the official example from here http://docs.oracle.com/javase/8/docs/technotes/guides/scripting/prog_guide/api.html a bit.
Now i created a minimal example to produce this exception.
It seems like, if a JS object is passed to Java via return value, it is different to the case JS calls a Java object's method and passes the object.
public class InvokeScriptMethod {
static Object o1;
public static class Context {
public void add( Object o ){
InvokeScriptMethod.o1 = o;
}
}
public static void main(String[] args) throws Exception {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("nashorn");
engine.put("ctx", new Context());
engine.eval("function bla(){\n"
+ "var obj = new Object();\n"
+ "obj.var1 = 3;\n"
+ "obj.hello = function(name) { print('Hello, ' + this.var1 + ' ' + name); this.var1++; };\n"
+ "ctx.add(obj);\n"
+ "return obj;\n"
+ "}");
Invocable inv = (Invocable) engine;
Object obj = inv.invokeFunction("bla");
System.out.printf("retrieved as return value : %s %s\n", obj.getClass(), obj);
System.out.printf("retrieved via call to java object: %s %s\n", o1.getClass(), o1);
inv.invokeMethod(obj, "hello", "Script Method!");
inv.invokeMethod(o1, "hello", "Script Method!"); // <-- exception
}
}
program output:
retrieved as return value : class jdk.nashorn.api.scripting.ScriptObjectMirror [object Object]
retrieved via call to java object: class jdk.nashorn.internal.scripts.JO jdk.nashorn.internal.scripts.JO#105fece7
Hello, 3 Script Method!
Exception in thread "main" java.lang.IllegalArgumentException: no current Global instance for nashorn
obj is a ScriptObjectMirror as it is expected, o1 is an internal object.
http://cr.openjdk.java.net/~sundar/8023631/webrev.00/src/jdk/nashorn/api/scripting/NashornScriptEngine.java.html line 481 shows how this exception is thrown.
So I think, there is something wrong by wrapping the "naked" JS object into a ScriptObjectMirror when passing as argument to Java.
Now I have 2 questions:
1. Is this a bug in my code? Or a bug in the Java8 nashorn?
2. Is there a way that i can work around this exception bug keeping the same call scheme.
Thanks Frank
I've found that calling inv.invokeFunction does work. So instead of calling inv.invokeMethod attempting to directly call a method on a javascript object, I proxy all invocations through an intermediate javascript global scope function (proxyMethodCall).
var test = {
init = function() {
// call back into my Scala code to register a callback to invoke the method "foo"
// for a particular condition.
registerCallback(this, "foo", "myarg");
},
foo: function(arg) {
// here I am in my foo function
}
}
// the Scala code knows to call this proxy method as a workaround
// to invoke the method in the target (thiz) javascript object.
function proxyMethodCall(thiz, methodName, arg) {
thiz[methodName].call(thiz, arg);
}
// Scala code...
val inv = engine.asInstanceOf[Invocable]
inv.invokeFunction("proxyMethodCall", thiz, methodName, methodArgument)
for me, the question is now clearly a Java 8 bug.
I found the workaround to integrate the Java 7 JavaScript engine into my project.
This should work until the bug is fixed.
See this description on how to do it:
https://wiki.openjdk.java.net/display/Nashorn/Using+Rhino+JSR-223+engine+with+JDK8
cu
Frank
I want to call the Groovy scripts from Java and refresh the Groovy scripts periodically.
For example ,
public class AppTest {
public static void main(String args[]) throws Exception {
TestVO test = new TestVO();
AnotherInput input = new AnotherInput();
test.setName("Maruthi");
input.setCity("Newark");
GroovyClassLoader loader = new GroovyClassLoader(AppTest.class.getClassLoader());
Class groovyClass = loader.parseClass(new File("src/main/resources/groovy/MyTestGroovy.groovy"));
GroovyObject groovyObject = (GroovyObject) groovyClass.newInstance();
Object[] inputs = {test,null};
Map<String,String> result = (Map<String, String>)groovyObject.invokeMethod("checkInput", inputs);
System.out.println(result);
}
}
And my Groovy script is
class MyTestGroovy {
def x = "Maruthi";
def checkInput = { TestVO input,AnotherInput city ->
if(input.getName().equals(x)) {
input.setName("Deepan");
println "Name changed Please check the name";
} else {
println "Still Maruthi Rocks";
}
Map<String, String> result = new HashMap<String,String>();
result.put("Status", "Success");
if(city != null && city.getCity().equalsIgnoreCase("Newark")) {
result.put("requested_State", "Newark");
}
return result;
}
def executeTest = {
println("Test Executed");
}
}
How efficient my memory would be managed when I create multiple instances of groovy script and execute the script. Is it advisable to use a number of Groovy scripts as my customized rule engine. Please advise.
It is usually better to have several instances of the same script, than parsing the class every time you want to create an instance. Performance wise that is because compiling the script takes some time, you have to pay in addition to creating an instance. Memory wise you use up the number of available classes up faster. Even if old classes are collected, if you have many scripts active, it can happen... though that normally means hundreds or even thousands of them (depends on the jvm version and your memory settings)
Of course, once the script changed, you will have to recompile the class anyway. So if in your scenario you will have only one instance of the class active at the same time, and a new instance is only required after a change to the source, you can recompile every time.
I mention that especially, because you might even be able to write the script in a way, that let's you reuse the same instance. But it is of course beyond the scope of this question.
I have javascript file (jalali.js) which it have a lot of functions.
I want to call one of this functions in my java web application project (I mean somefile.Class file)
I had some research and i found these two methods:
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("JavaScript");
engine.eval("print('Hello, World')");
But I can not understand how to call my js file (jalali.js) and how should i call my function
I will put function detail code here (from jalali.js)
JalaliDate.gregorianToJalali = function(g_y, g_m, g_d)
{
g_y = parseInt(g_y);
g_m = parseInt(g_m);
g_d = parseInt(g_d);
var gy = g_y-1600;
var gm = g_m-1;
var gd = g_d-1;
...
...
return [jy, jm, jd];
}
I want to use that function in my java application (MyClass.class)
public class TaskListModel extends BaseModel{
private Date gDate;
private String jalaliDate;
public void setGDate(Date gDate) {
this.gDate= gDate;
this.jalaliDate = Here i need call the js function ;
}
Well if this is the Rhino engine from 1.6 Java, then you can evaluate the code in jalali.js line by line - keeping the instance of engine alive through the runtime of the file. Also you can then execute the function like this: engine.eval("myfunction(arg1, arg2);");
I am not sure what you are trying to achieve
Step1. Read a line of the jalali.js file
Step2. engine.eval() the line
Step3. check if EOF - if yes, go to Step4 else go to Step1
Step4. engine.eval("your_function(arg1, arg2);");
a simple solution would be you read the whole file and append to it the function call you want to make and pass the modified contents to the eval method. so the final content passed to eval would take the form of
//
script in your .js file
//
return functionInYourJs(arg1, arg2);
Probably once the file is read you can cache it to avoid repeated disk reads.