在Rhino Javascript中共享Java对象

3
让我首先承认,我对JavaScript一窍不通。所以这个问题可能在基础知识方面并不很严谨,并且可能缺乏足够的信息来帮助我。
背景
我们的组织有一个基于Eclipse的内部JavaScript IDE。我们所要做的就是编写JavaScript脚本并直接执行它们。我的猜测是它使用Rhino,因为我在一些异常的堆栈跟踪中看到了它。
我的代码跨越3个“.js”文件。
Script-1:声明全局变量并将它们实例化为Java对象
importClass(java.util.HashMap);
var hmTCResult = new HashMap();

脚本-2:使用来自脚本-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在Script 1中运行良好。

我已经阅读了JavaScript中的范围和上下文,但由于IDE中没有明确显示,我还没有突破它。

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


我认为对你有影响的“Java”对象并没有共享。请向我们展示您代码的相关部分,即脚本2中该函数的声明、脚本3中的调用,并指出您想要使用但未被使用的变量。 - Bergi
你能提供一些代码吗? - Aadit M Shah
问题已更新,附上了代码。很抱歉我无法提供完整的代码。提前感谢您的帮助。 - wanderlust
我对Java/Rhino没有经验,但Script-2不是有效的JavaScript标识符。请将其命名为Script2Script_2 - J. K.
感谢Bergi的回复。我尝试删除var关键字,但没有成功。我在Google上搜索并发现我可以使用window.hmTCResult将其显式添加到全局对象中。但是,由于这不是可以在浏览器中执行的JavaScript,因此我不确定这是否有效。还有其他方法可以将其分配给全局对象吗? - wanderlust
显示剩余2条评论
3个回答

1

这个很好用,只需要调整一下作用域并设置原型搜索即可:

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.exit() 后仍然存在。


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而新分配了引擎,则上下文已被清除。
这篇文章并不是真正的答案,但太长了,不能作为评论。

谢谢Aubin。正如我所提到的,虽然基于Eclipse,但我的工具更像JavaScript IDE。我在工具中没有看到Java代码。 - wanderlust
好的,我不太明白。我已经重新标记了您的问题,删除了Java标签,因为它不适用。 - Aubin
Aubin,我不同意。如果你看到我的问题,我正在JavaScript中使用Java类。因此,Java标签是相关的。 - wanderlust

0

根据您提供的信息,如果您更改后的记录完全正确,并且脚本在不同的作用域中运行,其中全局作用域是其父级,则我的猜测是这样的。

因此,我猜测changeStatus在第三个脚本中工作的原因是没有为它声明var。因此,在缺少其他配置的情况下,这将被定义为顶层或全局范围内共享的变量。

我的猜测是hmTCResult之所以不起作用是因为它使用关键字var声明为局部变量。如果所有脚本都在顶层作用域中运行,则这将在全局对象上定义一个变量。但是,如果每个脚本都在自己的作用域中运行,则这将仅在脚本1的作用域中定义一个变量。您在脚本2的作用域内看不到问题,因为在执行脚本3之前,没有人执行脚本2中的代码。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接