Forum Stats

  • 3,757,881 Users
  • 2,251,286 Discussions
  • 7,869,962 Comments

Discussions

Invoking invokeFunction("someJSbject") twice both have same properties

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