javascript - 如何使用 Nashorn 的 JSObject 进行字符串连接

标签 javascript java nashorn

意图

我正在使用 Java 8u60(不是 8u51,这很重要!)并且正在使用其 Nashorn JavaScript 引擎。我通过扩展 AbstractJSObject 创建了自己的 JSObject。它应该包装一个 org.json.JSONObject 并使其像脚本引擎中的实际 JavaScript 对象一样工作。鉴于 javaAPI 是一个放入 ScriptContext 中的 Java 对象,生成的对象应该如下所示:

var jsonObject = javaAPI.doSomethingThatReturnsAJSONObject();
var foo = jsonObject.foo
jsonObject.foo = "bar";
delete jsonObject.foo;
var message = "JSON: " + jsonObject;

代码

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)
    [...]

我需要做什么才能让 Nashorn 调用 toString() 方法,以便 message 包含类似 JSON: {"foo":"的内容栏}

最佳答案

解决方案

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

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

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

我将以下代码添加到 JSONObjectJavaScriptAdapter 以使字符串连接正常工作:

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

关于javascript - 如何使用 Nashorn 的 JSObject 进行字符串连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32307231/

相关文章:

javascript - 捕获 Nashorn 的全局变量

Java 8 Nashorn JJS – javascript 控制台

javascript - 我如何强制 tinyMCE 不将 <b> 标签转换为 <strong> 标签?

javascript - 即使建立连接后,Flask socketio 也没有收到来自 javascript 的任何消息

java - 如何处理 Hibernate 和数据库模式中名称的国际化

java - resultSet.next() 是做什么的

javascript - 当 IE 8 中的尺寸更改(高度、宽度)时,VML 中的可拖动元素会卡住

javascript - 有什么方法可以改变 Slick 轮播中从左到右的方向吗?默认它从右到左方向

java.lang.ClassNotFoundException : Didn't find class "com.google.android.gms.measurement.AppMeasurementJobService" on path: DexPathList

java - Java 中是否有 Nashorn 的 ScriptObjectMirror 的公共(public)和具体实例?