如何使字符串连接与Nashorn的JSObject一起工作

时间:2015-08-31 08:46:58

标签: javascript java nashorn

意图

我正在使用Java 8u60( 8u51,这很重要!)并正在使用其Nashorn JavaScript引擎。我通过扩展AbstractJSObject创建了自己的org.json.JSONObject。它应该包装javaAPI并使其像脚本引擎中的实际JavaScript对象一样工作。鉴于ScriptContext是放在var jsonObject = javaAPI.doSomethingThatReturnsAJSONObject(); var foo = jsonObject.foo jsonObject.foo = "bar"; delete jsonObject.foo; var message = "JSON: " + jsonObject; 中的Java对象,生成的对象应该像这样使用:

public class JSONObjectJavaScriptAdapter extends AbstractJSObject {

    private final JSONObject jsonObject;

    public JSONObjectJavaScriptAdapter(final JSONObject jsonObject) {
        this.jsonObject = jsonObject;
    }

    @Override
    public void removeMember(String name) {
        jsonObject.remove(name);
    }

    @Override
    public void setMember(String name, Object value) {
        jsonObject.put(name, value);
    }

    @Override
    public Set<String> keySet() {
        return jsonObject.keySet();
    }

    @Override
    public boolean hasMember(String name) {
        return jsonObject.has(name);
    }

    @Override
    public Object getMember(String name) {
        return jsonObject.get(name);
    }

    @Override
    public String toString() {
        return jsonObject.toString();
    }
}

代码

var message = "JSON: " + jsonObject;

问题

除了字符串连接外,一切正常。写点像

org.json.JSONException: JSONObject["valueOf"] not found.
    at org.json.JSONObject.get(JSONObject.java:476)
    at my.JSONObjectJavaScriptAdapter.getMember(JSONObjectJavaScriptAdapter.java:50)
    at jdk.nashorn.api.scripting.DefaultValueImpl.getDefaultValue(DefaultValueImpl.java:42)
    at jdk.nashorn.api.scripting.AbstractJSObject.getDefaultValue(AbstractJSObject.java:269)
    at jdk.nashorn.api.scripting.AbstractJSObject.getDefaultValue(AbstractJSObject.java:285)
    at jdk.nashorn.internal.runtime.JSType.toPrimitive(JSType.java:512)
    at jdk.nashorn.internal.runtime.JSType.toPrimitive(JSType.java:480)
    at jdk.nashorn.internal.runtime.JSType.toPrimitive(JSType.java:462)
    at jdk.nashorn.internal.runtime.ScriptRuntime.ADD(ScriptRuntime.java:563)
    at jdk.nashorn.internal.scripts.Script$Recompilation$2$16$configuration.main(src/test/resources/de/ams/inm/workflow/engine/javascript/async/configuration.js:23)
    at jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:640)
    at jdk.nashorn.internal.runtime.ScriptFunction.invoke(ScriptFunction.java:228)
    at jdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:393)
    at jdk.nashorn.api.scripting.ScriptObjectMirror.callMember(ScriptObjectMirror.java:199)
    at jdk.nashorn.api.scripting.NashornScriptEngine.invokeImpl(NashornScriptEngine.java:383)
    at jdk.nashorn.api.scripting.NashornScriptEngine.invokeFunction(NashornScriptEngine.java:190)
    [...]

将导致以下异常:

toString()

我需要做些什么才能让Nashorn调用message方法,以便JSON: {"foo":"bar}包含{{1}}之类的内容?

2 个答案:

答案 0 :(得分:2)

解决方案

事实证明,Nashorn遵循ECMA规范。重要的部分是The Addition operator ( + )[[DefaultValue]]

如果+运算符用于对象,则使用[[DefaultValue]]函数将这些对象转换为基元。默认[[DefaultValue]]实现使用valueOftoString函数将对象转换为基元。

对象可以覆盖[[DefaultValue]]函数以提供自定义到基元的转换。从Java 8u60开始,这也可能在Nashorn中,通过覆盖AbstractJSObject.getDefaultValue(Class)

我将以下代码添加到JSONObjectJavaScriptAdapter以使字符串连接工作为例外:

@Override
public Object getDefaultValue(Class<?> hint) {
    return toString();
}

答案 1 :(得分:0)

此外,如果JSObject.getMember可以处理任何抛出的异常,并且可能返回null或适当的值 - 而不是传播异常。在您的示例中,org.json.JSONObject.get在未找到属性时抛出异常。

另一件事:你可以返回一个&#39;函数值&#39;为&#39; toString&#39;或者&#39; valueOf&#39; property - 以便按ECMAScript中的指定调用toString / toNumber转换。