Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I call a method of a Java instance from JavaScript?

I'm using the Mozilla Rhino JavaScript emulator. It allows me to add Java methods to a context and then call them as if they were JavaScript functions. But I can't get it to work except when I use a static method.

The problem is this part of the documentation:

If the method is not static, the Java 'this' value will correspond to the JavaScript 'this' value. Any attempt to call the function with a 'this' value that is not of the right Java type will result in an error.

Apparently, my Java "this" value doesn't correspond with the one in JavaScript and I have no idea how to make them correspond. In the end, I'd like to create an instance in Java, and install a couple of methods from it in the global scope, so I can initialize the instance from Java but use it in my scripts.

Does anyone have some example code for this?

like image 277
Aaron Digulla Avatar asked Aug 09 '10 16:08

Aaron Digulla


1 Answers

@Jawad's answer is great, but it still requires the parentScope to be a parent of the object you're trying to insert. If you want to add global functions into the scope created with initStandardObjects(), you have to use shared scope (which is sort of explained in the docs but lacks a full example).

Here's how I did it (this is Android so please excuse the Kotlin):


/**
 * Holds the global or "window" objects that mock browser functionality.
 */
internal class Global() {

  fun requestAnimationFrame(callback: BaseFunction) {
    ...
  }

  fun setTimeout(callback: BaseFunction, delay: Int): Int {
    ...
  }

  fun clearTimeout(id: Int) {
    ...
  }

  internal fun register(context: Context, scope: Scriptable): Scriptable {
    return context.wrapFactory.wrapAsJavaObject(context, scope, this, Global::class.java)
  }
}

/**
 * Creates the root scope containing the StandardObjects, and adds Global functions to it.
 */
fun createRootScope(): Scriptable {
  val context = Context.enter()
  val sharedScope = context.initSafeStandardObjects(null, true)

  val rootScope = Global().register(context, sharedScope)
  rootScope.prototype = sharedScope;
  rootScope.parentScope = null;

  return rootScope
}
like image 162
phreakhead Avatar answered Oct 19 '22 23:10

phreakhead