Search code examples
javajavascriptnashorn

Sharing JavaScript arrays and objects between multiple nashorn ScriptEngines


I am having a problem with nashorn, and I don't quite get how native constructors work (Object, Array, etc).

My issue involves several ScriptEngines through the lifecycle of an application, and some of them can create functions.

I try to use those functions in new ScriptEngines, the problem is that I cannot check if an object is of a given type (array instanceof Array), because that Array wasn't generated by this instance's Array constructor.

Here is a test to replicate it:

def "Just testing"() {                                                                                                                                      
when:                                                                                                                                                     
  def manager = new ScriptEngineManager()                                                                                                                 
  def engine1 = manager.getEngineByName("nashorn")                                                                                                        
  def engine2 = manager.getEngineByName("nashorn")                                                                                                                

  def arrImpl = engine1.eval("[]")                                                                                                                        

  engine2.context.setAttribute("arr", arrImpl, ScriptContext.ENGINE_SCOPE)                                                                                

  def val = engine2.eval("arr instanceof Array")                                                                                                          

then:                                                                                                                                                     
  val == true                                                                                                                                             

}

I read this article https://wiki.openjdk.java.net/display/Nashorn/Nashorn+jsr223+engine+notes and tried to solve it like this, but still having no luck

def "Just testing"() {                                                                                                                                      
when:                                                                                                                                                     
  def manager = new ScriptEngineManager()                                                                                                                 
  def engine1 = manager.getEngineByName("nashorn")                                                                                                        
  def engine2 = manager.getEngineByName("nashorn")                                                                                                        

  def context = new SimpleScriptContext()                                                                                                                 
  def bindings = engine1.getContext().getBindings(ScriptContext.ENGINE_SCOPE)                                                                             
  context.setBindings(bindings, ScriptContext.ENGINE_SCOPE)                                                                                                              

  def arrImpl = engine1.eval("[]")                                                                                                                        


  context.setAttribute("arr", arrImpl, ScriptContext.ENGINE_SCOPE)                                                                                        
  def val = engine2.eval("arr instanceof Array", context)                                                                                                 

then:                                                                                                                                                     
  val == true                                                                                                                                             

}

Do you have any idea of how to make it work?


Solution

  • Each engine's ENGINE_SCOPE bindings is associated with a Nashorn Global scope object. "Array", "Object" etc. are JS built-in constructors defined in global scope. So such constructors are different in different global scopes. So, you can't compare object from another global scope with "instanceof". But because of smart dynalink based linking, nashorn can still allow you to access properties of such "cross global" objects. You can, for example, access "length" property, elements of array from script run in another engine using normal property/element access, method call syntax. Hope this helps.