Search code examples
javanashornscriptengine

Nashorn ScriptEngine. How to share "org" object from Global scope to Local scope?


Nashorn script engine doesn't share "com" and "org" objects/namespaces from Global scope to Engine scope. Because "com" and "org" are Java packages available from engine.

In example I put a and org variables to Global scope of engine2.

  • a = 3 is shared
  • org = 10 exists in GLOBAL_SCOPE but is not shared to ENGINE_SCOPE

Code:

public static void main(String[] args) throws ScriptException {
    ScriptEngineManager manager = new ScriptEngineManager();
    ScriptEngine engine = manager.getEngineByName("JavaScript");
    Bindings bindings = engine.createBindings();
    bindings.put("a", 3);
    bindings.put("org", 10);
    log("bingings-org", bindings.get("org"));
    manager.setBindings(bindings);

    ScriptEngine engine2 = manager.getEngineByName("JavaScript");
    log("global-a", engine2.getBindings(ScriptContext.GLOBAL_SCOPE).get("a"));
    log("local-a", engine2.get("a"));
    log("global-org", engine2.getBindings(ScriptContext.GLOBAL_SCOPE).get("org"));
    log("local-org", engine2.get("org"));
}
  1. Is there a way to share "org" and "com" packages from Global scope to Local scope?
  2. Does any documentation exist where the situation would be described?

Solution

  • When a script global variable is searched, the search order is ENGINE_SCOPE first and then the GLOBAL_SCOPE. The ENGINE_SCOPE Bindings of Nashorn engine is ECMAScript "global" object wrapped as javax.script.Bindings object. As you observed, ENGINE_SCOPE has mapping for "org", "com" etc. - which are Java package prefix objects. So, these will hide any "org", "com" etc. from GLOBAL_SCOPE bindings. Two solutions:

    1. You have "context" variable exposed to script. So, you could pick up GLOBAL_SCOPE mapping using the same.

      private static void log(String msg, Object obj) {
          System.out.println(msg + " " + obj);
      }
      
      public static void main(String[] args) throws ScriptException {
          ScriptEngineManager manager = new ScriptEngineManager();
          Bindings bindings = new SimpleBindings();
          bindings.put("a", 3);
          bindings.put("org", 10);
          log("bingings-org", bindings.get("org"));
          manager.setBindings(bindings);
      
          ScriptEngine engine = manager.getEngineByName("JavaScript");
          log("global-a", engine.getBindings(ScriptContext.GLOBAL_SCOPE).get("a"));
          log("local-a", engine.get("a"));
          log("global-org", engine.getBindings(ScriptContext.GLOBAL_SCOPE).get("org"));
          log("local-org", engine.get("org"));
      
          // Use "context" to access GLOBAL_SCOPE "org" from script
          engine.eval(
              "var GLOBAL_SCOPE = javax.script.ScriptContext.GLOBAL_SCOPE;\n" +
              "var g = context.getBindings(GLOBAL_SCOPE);\n" +
              "print(g.get('org'))"); 
      }
      
    2. You can delete the "org", "com" etc. in ENGINE_SCOPE Bindings.

      private static void log(String msg, Object obj) {
          System.out.println(msg + " " + obj);
      }
      
      public static void main(String[] args) throws ScriptException {
          ScriptEngineManager manager = new ScriptEngineManager();
          Bindings bindings = new SimpleBindings();
          bindings.put("a", 3);
          bindings.put("org", 10);
          log("bingings-org", bindings.get("org"));
          manager.setBindings(bindings);
      
          ScriptEngine engine = manager.getEngineByName("JavaScript");
          log("global-a", engine.getBindings(ScriptContext.GLOBAL_SCOPE).get("a"));
          log("local-a", engine.get("a"));
          log("global-org", engine.getBindings(ScriptContext.GLOBAL_SCOPE).get("org"));
          log("local-org", engine.get("org"));
          // "org" in ENGINE_SCOPE hides GLOBAL_SCOPE "org".
          // delete the "org" in ENGINE_SCOPE
          // you could delete "org" from Java code as well using
          // "remove" method of Bindings object
          engine.eval("delete org");
          System.out.println("after deleting ENGINE_SCOPE org");
          log("local-org", engine.get("org"));
      }