Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sharing java objects in Rhino Javascript

Let me first start with admitting that I am a noob in JavaScript. So the question might not be very sound at the basics and might lack enough information to help me.

Background

My organisation has an internal Eclipse based IDE for JavaScript. All we have to do is write scripts in JavaScript and directly execute them. My guess is it uses Rhino since I have seen it in the stack trace of some exceptions.

My code runs across 3 ".js" files.

Script-1: Declare global variables and instantiate them as Java objects

importClass(java.util.HashMap);
var hmTCResult = new HashMap();

Script-2: Perform some actions using the global variables from Script-1

Script-2.prototype.run = function() {
hmTCResult.put("Result", "Fail");
};

changeStatus = function(strStatus){
hmTCResult.put("Result", strStatus);
};

Script-3: Call function in Script-2 which uses the global variables

changeStatus("Pass") 

Problem Definition

When from Script-3 I call the function in Script-2 it doesn't seem pick the instance variables and my function fails i.e. I get an exception "hmTCResult not set to the instance of an object." Please note that the the same variable hmTCResult works well in Script 1.

I have done some reading of the Scope and the Context in JavaScript but haven't been able to break through it, since I don't see it explicitly in the IDE.

I will be happy to provide more information if needed.

like image 790
wanderlust Avatar asked Jul 23 '26 16:07

wanderlust


1 Answers

This works fine, just juggle your scopes and get prototype search set up:

Context cx = Context.enter();
try {
    // Cache and reuse:
    ScriptableObject sealedSharedScope = cx.initStandardObjects(null,
            true);
    // Force the LiveConnect stuff to be loaded.
    String loadMe = "RegExp; getClass; java; Packages; JavaAdapter;";
    cx.evaluateString(sealedSharedScope, loadMe, "preLoadLazyLoad", 0,
            null);

    cx.evaluateString(sealedSharedScope, "varInRoot = 'blah';",
            "setVarInRoot", 0, null);

    // here you can put more cx.evaluateString calls to set up your
    // environment (eg. hmTCResult)

    // now connect a throw-away new scope into the hierarchy, with local
    // vars:
    Scriptable scope = cx.newObject(sealedSharedScope);
    // ensure that definitions in the root scope are found
    scope.setPrototype(sealedSharedScope);
    // ensure that new global variables are created in this scope (don't
    // use
    // var for them!)
    scope.setParentScope(null);

    cx.evaluateString(scope, "localVar = varInRoot;", "mySource", 0,
            null);
    assertEquals("blah", scope.get("localVar", scope).toString());
    // new var not in root:
    assertEquals(ScriptableObject.NOT_FOUND,
            sealedSharedScope.get("localVar", scope));
} finally {
    Context.exit();
}

Beware that scope.get doesn't search the prototype chain - gotta do that yourself!

Scopes are independent of Context and survive Context.exit().

like image 153
Georg Avatar answered Jul 25 '26 05:07

Georg



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!