在Rhino Javascript中共享java对象

时间:2012-10-21 15:14:33

标签: java javascript rhino

首先我要承认我是JavaScript中的菜鸟。所以问题在基础知识上可能不是很合理,可能缺乏足够的信息来帮助我。

背景

我的组织有一个基于Eclipse的内部IDE for IDE。我们所要做的就是用JavaScript编写脚本并直接执行它们。我的猜测是它使用了Rhino,因为我已经在一些例外的堆栈跟踪中看到过它。

我的代码遍历3个“.js”文件。

Script-1:声明全局变量并将它们实例化为Java对象

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

脚本-2:使用Script-1

中的全局变量执行一些操作
Script-2.prototype.run = function() {
hmTCResult.put("Result", "Fail");
};

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

脚本-3:脚本-2中的调用函数,它使用全局变量

changeStatus("Pass") 

问题定义

当我从Script-3调用Script-2中的函数时,它似乎没有选择实例变量而我的函数失败,即我得到一个异常“hmTCResult未设置为对象的实例。”请注意,相同的变量hmTCResult在脚本1中运行良好。

我已经在JavaScript中完成了对Scope和Context的一些阅读,但是还没有能够突破它,因为我没有在IDE中明确地看到它。

如果需要,我很乐意提供更多信息。

3 个答案:

答案 0 :(得分:0)

要在Java中评估js脚本,可以执行以下操作

ScriptEngine engine = new ScriptEngineManager().getEngineByMimeType( "text/javascript" );
Bindings bindings = engine.getBindings( ScriptContext.GLOBAL_SCOPE );
bindings.put( "varname", ... );
bindings.put( ... );
engine.put( ScriptEngine.FILENAME, script.toString());
engine.eval( new FileReader( script ));

如果3个脚本在同一个引擎/绑定中加载,则没问题,但如果新分配引擎执行script3,则上下文已被清除。

这篇文章不是一个真正的答案,但是要发表评论的时间太长了。

答案 1 :(得分:0)

我的猜测,如果没有更多信息,并且假设您的修改后的成绩单绝对正确,那么您的脚本将在不同的范围内运行,所有范围都以全局范围作为父级。

因此,我的猜测是changeStatus在第三个脚本中起作用的原因是因为它没有var声明。因此,如果没有其他配置,这将被定义为顶级或全局范围内的变量,该变量在三个脚本中共享。

我的猜测是hmTCResult 工作的原因是它是用关键字var声明的,表示一个局部变量。如果所有脚本都在顶级作用域中运行,则会在全局对象上定义一个变量。但是如果每个脚本都在自己的范围内运行,那么这只会在脚本1的范围内定义一个变量。你不会在脚本2的范围内看到问题,因为在脚本3之前没有人在脚本2中执行代码执行。

答案 2 :(得分:0)

这很好用,只需要调整范围并设置原型搜索:

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();
}

请注意scope.get不会搜索原型链 - 必须自己做!

范围独立于Context并且存在于Context.exit()。