Hi Guys,
We are moving from rhino to javax.script. Well you can guess that is a major step in our development of our software. Of course I didn’t expect it to just be a breeze. I have found a very strange feature of javax.script package.
I have a very simple js script:
load("nashorn:mozilla_compat.js");
function JSDevice() {
this.deviceType = "";
this.deviceId = "";
return this;
}
And a Java code:
import java.io.File;
import java.io.FileReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
import javax.script.Bindings;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
/**
* @author jdalecki
*
*/
public class Main {
/**
* @param args
*/
public static void main(String[] args) {
Main m = new Main();
m.exposeTheBug();
}
private void exposeTheBug() {
ScriptEngine engine = (new ScriptEngineManager()).getEngineByName("JavaScript");
List<Bindings> allDevices = new ArrayList<Bindings>();
String scriptFilename = <point to the folder where you saved the js script file>
try {
File fName = new File(scriptFilename);
Reader scriptReader = new FileReader(fName);
engine.eval(scriptReader);
Invocable invocable = (Invocable) engine;
System.out.println("Creating two different JSDevice objects:");
System.out.println("\tFirst with the properties:");
System.out.println("\t\tdeviceType=JSDevice1.type");
System.out.println("\t\tdeviceId=JSDevice1.id");
System.out.println("\tSecond with the properties:");
System.out.println("\t\tdeviceType=JSDevice2.type");
System.out.println("\t\tdeviceId=JSDevice2.id");
// Step 1
System.out.println("First object created:");
Bindings jsDevice1 = (Bindings)invocable.invokeFunction("JSDevice");
jsDevice1.put("deviceType", "JSDevice1.type");
jsDevice1.put("deviceId", "JSDevice1.id");
for(String key : jsDevice1.keySet())
{
if(key.equals("deviceType") || key.equals("deviceId"))
{
Object obj = jsDevice1.get(key);
System.out.println(obj);
}
}
allDevices.add(jsDevice1);
System.out.println("");
// Step 2
System.out.println("Second object created:");
Bindings jsDevice2 = (Bindings)invocable.invokeFunction("JSDevice");
jsDevice2.put("deviceType", "JSDevice2.type");
jsDevice2.put("deviceId", "JSDevice2.id");
for(String key : jsDevice2.keySet())
{
if(key.equals("deviceType") || key.equals("deviceId"))
{
Object obj = jsDevice2.get(key);
System.out.println(obj);
}
}
allDevices.add(jsDevice2);
System.out.println("");
// Summary
System.out.println("In summary: Both JSDevice objects point to the properties I set in the second JSDevice object, why?");
for(Bindings b : allDevices)
{
for(String key : b.keySet())
{
if(key.equals("deviceType") || key.equals("deviceId"))
{
System.out.println("Device: "+key+" Value="+b.get(key));
}
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
The problem description:
As you can see I am creating sequentially two Java Script object calling engine invokeFunction("JSDevice"). That is all good so far.
However when I set the properties (“deviceType” and “deviceId”) on both of them, the last setting seems to overwrite the properties of the first object.
Both “JSDevice” objects point to the properties I set in the second JSDevice object, why?
Regards,
Janusz