4

Javascript中,我有以下代码:

var r=applet.foo({var0:99,var1:'foo',var2:applet});

在我的Java小程序中,我有以下内容:

public JSObject foo(JSObject args){
    System.out.println("The function is correctly invoked");
    //In fact, the following works perfectly:
    System.out.println("var1 is:"+(String)args.getMember("var1"));
    JSObject w=JSObject.getWindow(this);
    JSObject j=(JSObject)w.eval("new Object();");
    Map m=new Hashmap();

    //TODO here all the keys and values of args should be added to m

    m.put("hello","world");

    //TODO here all the keys and values of m should be added to j

    return j;
}

如何才能做到这一点?(待办事项


阅读http://docstore.mik.ua/orelly/web/jscript/ch19_06.html,我注意到 JSObject 有一个 getSlot 方法,但如果我这样做

args.getSlot(0)

我只有一个例外:

netscape.javascript.JSException: No such slot 0 on JavaScript object
...
4

3 回答 3

3

不幸的是,Errandir 的解决方案仅在您知道可用于访问要获取其属性名称的对象的全局变量名称时才有效。您需要知道此名称才能向keys对象添加方法,并稍后使用JSObjectcall方法调用它。当然,您可以将对象的全局名称传递给 Java(如果有的话)。此解决方案看起来不太好,尤其是当您无法在全局上下文中引用您的对象时。

作为替代方案,我建议在评论中使用this' JSObjecteval方法,假设它会完成所有工作。它确实如此。但令人失望的是,它只能在 Mozilla Firefox 和 Opera 中按预期工作。在 Internet Explorer 9 和 Google Chrome(在 Windows 7 和 Ubuntu 12.04 LTS 下测试)this中,eval方法总是指小程序的文档窗口,而忽略JSObject实际代表的 JavaScript 对象实例。我不知道这是一个错误还是这些浏览器对LiveConnect的支持非常差。

好消息是在适当的上下文中执行指定函数的call方法。JSObject牢记这一点,我终于找到了如何检索 JavaScript 对象属性名称列表的解决方案。这个想法是使用eval方法在全局上下文中定义一个临时函数。该函数必须接收我们想要获取其属性的 JavaScript 对象,并将这些属性的名称作为数组返回。之后,我们可以通过传递相关 JavaScript 对象的 Java 表示的JSObject'方法调用临时函数(在我下面的方法中或在问题中听起来)。最后,可以删除临时功能。calljsObjectargs

public static ArrayList<String> getJsObjectPropertiesNames(Applet applet, JSObject jsObject) {

    if (applet == null || jsObject == null)
        return null;

    // Retrieving global context - a JSObject representing a window applet belongs to
    JSObject globalContext;
    try {

        globalContext = JSObject.getWindow(applet);
    }
    catch (JSException ex) {

        return null;
    }

    // Checking whether passed object is not an array
    try {

        jsObject.getSlot(0);
        return null;
    }
    catch (JSException e) {

    }

    String keysFunctionName = String.format("_getKeys%d", Calendar.getInstance().getTimeInMillis());
    jsObject.eval("window['" + keysFunctionName + "'] = function(jsObject) { return Object.keys(jsObject) }");
    JSObject propertiesNamesJsObject = (JSObject)globalContext.call(keysFunctionName, new Object[] { jsObject });
    jsObject.eval("delete(window['" + keysFunctionName + "'])");

    ArrayList<String> propertiesNames = new ArrayList<>();
    try {

        int slotIndex = 0;
        while (true) {

            Object propertyName = propertiesNamesJsObject.getSlot(slotIndex);
            if (propertyName instanceof String)
                propertiesNames.add((String)propertyName);
            slotIndex++;
        }
    }
    catch (JSException e) {

    }

    return propertiesNames;
}
于 2012-12-20T23:33:06.033 回答
1

作为一种解决方案,您可以按照此处keys的建议定义方法(您可以在您的 java 代码中使用)。然后你可以得到像这样的键:JSObject.eval(...)

JSObject keys = (JSObject)args.call("keys", Collections.EMPTY_LIST);
keys.getSlot(0);
于 2012-10-17T10:21:10.317 回答
-1

下面我打印一个字符串,请修改它以获得您需要的任何内容。

public final static String getKeys = "{var keys = [];for (var key in this) {keys.push(key);} keys;}";

private static String printProperties(final Object o,
                                      final boolean printType,
                                      final int level,
                                      final String tab) {
    final StringBuilder sb = new StringBuilder(100);
    if (printType) {
        sb.append("(");
        sb.append(o.getClass().getSimpleName());
        sb.append(") ");
    }
    if (o instanceof JSObject) {
        sb.append("{\n");
        final JSObject js = (JSObject) o;
        final JSObject keys = (JSObject) js.eval(getKeys);
        boolean needComma = false;
        for (int i = 0;; i++) {
            final String key = (String) keys.getSlot(i);
            if ((key != null) && !(key.equals("undefined"))) {
                final Object val = js.getMember(key);
                if (!needComma) {
                    needComma = true;
                } else {
                    sb.append(",\n");
                }
                sb.append(multitab(tab, level));
                sb.append(key);
                sb.append(":");
                sb.append(printProperties(val, printType, level + 1, tab));
            } else {
                break;
            }
        }
        sb.append("\n");
        sb.append(multitab(tab, level - 1));
        sb.append("}");
    } else {
        sb.append(o);
    }
    return sb.toString();
}

private final static String tab = "  ";

private static String multitab(final String tab,
                               int i) {
    final StringBuilder sb = new StringBuilder();
    while (i-- > 0) {
        sb.append(tab);
    }
    return sb.toString();
}
于 2015-08-07T02:13:52.657 回答