向 Nashorn 脚本提供 JavaScript 日期

Supply JavaScript date to Nashorn script

我正在 Java 中开发一个 API,它允许用户编写脚本并访问传入的一组特定方法(以 API 对象的形式) 由 Nashorn 脚本引擎提供。

我想在 JavaScript 中调用函数 getDate(),它将 return 一些任意日期(作为本机 JavaScript 日期)提供自Java 侧。

我曾尝试简单地在 API 对象上放置一个 org.java.util.Date,但这不会表现得像 JS 日期。目标是让对 JS 有经验的最终用户尽可能简单。

Java 示例:

public class MyAPI {
    public void log(String text){
        System.out.println(text);
    }

    public Date getDate(){
        // Return something that converts to a native-JS date
    }

    public static void main(){
        // MyClassFilter implements Nashorn's ClassFilter
        ScriptEngine engine = new NashornScriptEngineFactory().getScriptEngine(new MyClassFilter());
        ((Invokable) engine).invokeFunction("entryPoint", new MyAPI());
    }

Java脚本示例

function entryPoint(myApi){
    var date = myApi.getDate();
    myApi.log(date.getMinutes());
}

Nashorn 引擎有它在内部使用的对象,这些对象代表 Javascript 对象。正如您猜到的 java.util.Date != new Date()(在 javascript 中)。该引擎使用一个名为 jdk.nashorn.internal.objects.NativeDate 的 class 来表示其 JS 日期。

如果我正在构建它,我不会在 Java 中构建 NativeDate,而是在 Java 脚本中为 MyApi 对象创建一个包装器,它将包含一些其他原生 JS 方法,例如 getDate().

var MYAPI_JAVASCRIPT = {
    log: function() {
        print(arguments);
    },
    getDate: function() {
        return new Date();
    }
}

然后您可以将该对象作为方法参数传递。


但是,如果您真的打算在 Java 代码中使用 NativeDate,那么您可以像这样构造一个:

public NativeDate getDate() {
    return (NativeDate) NativeDate.construct(true, null);
}

jdk.nashorn.internal.* 软件包是 nashorn 内部实现 类。无法保证这些不会在 JDK 版本之间被更改或删除。除了周围有安全管理器外,直接从 java 代码访问这些包会导致抛出 SecurityException!使用 jdk9 模块化 jdk,这些包不是从 nashorn 模块导出的包,因此 javac 甚至不会在 jdk9![=11= 中编译您的代码]

我建议在用户 "ug_" 的回答中使用 JS 包装器(解决方案 1)。如果您确实必须从 Java 调用,您可以使用从 jdk.nashorn.api.scripting 包导出的 API。

如果 "engine" 是你的 javax.script.ScriptEngine 的 nashorn,那么你可以执行如下操作:

import jdk.nashorn.api.scripting.*;

..

public Object getDate() {
    // get JS Date constructor object - you can get once and store
    // as well/
    JSObject dateConstructor = (JSObject) engine.eval("Date");
    // now do "new" on it
    return dateConstructor.newObject();
}

有了它,您的 JS 脚本可以在您的 API 对象上调用 "getDate()" 并获得一个 JS 日期对象。请注意,您还可以将构造函数参数传递给 newObject 方法调用(它是一个 Java 可变参数方法)。