Предоставить дату JavaScript скрипту Nashorn

Я работаю над API на Java, который позволяет пользователям писать сценарии и получать доступ к определенному набору методов, которые передаются (в виде объекта API) механизмом сценариев Nashorn.

Я хочу в JavaScript вызвать функцию getDate(), которая вернет некоторую произвольную дату (как собственную дату JavaScript), предоставленную со стороны Java.

Я попытался просто поместить org.java.util.Date в объект API, но это не будет вести себя как дата 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());
    }

Пример JavaScript

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

person John Brink    schedule 13.10.2015    source источник


Ответы (2)


У механизма Nashorn есть объекты, которые он использует внутри, которые представляют объекты Javascript. Как вы уже догадались, java.util.Date != new Date() (в javascript). Движок использует класс с именем jdk.nashorn.internal.objects.NativeDate для представления своей даты JS.

Если бы я создавал это, я бы не создавал NativeDate на Java, а вместо этого имел бы оболочку в Javascript для объекта MyApi, которая содержала бы несколько других собственных методов JS, таких как getDate().

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

Затем вы можете передать этот объект в качестве параметра метода.


Однако, если вы действительно настроены использовать NativeDate в своем Java-коде, вы можете создать его следующим образом:

public NativeDate getDate() {
    return (NativeDate) NativeDate.construct(true, null);
}
person ug_    schedule 13.10.2015
comment
Спасибо, второй вариант помог! К вашему сведению, мне нужно было сделать это таким образом, потому что методы в API вызывают много кода Java. - person John Brink; 13.10.2015
comment
@MoscowModder К вашему сведению, если вы ищете собственный класс для любого объекта Javascript, вы можете использовать print(Date.prototype), конечно, замените Date любым объектом, который вы ищете. В случае Date вы получите что-то вроде: jdk.nashorn.internal.objects.NativeDate$Prototype@b7f23d9 - person ug_; 14.10.2015

Пакеты jdk.nashorn.internal.* представляют собой классы внутренней реализации nashorn. Нет гарантии, что они не будут изменены или удалены между версиями JDK. Кроме того, при наличии менеджера безопасности прямой доступ к этим пакетам из java-кода приведет к созданию SecurityException! С модульным jdk jdk9 эти пакеты не экспортируются из модуля nashorn, поэтому javac даже не будет компилировать ваш код в jdk9!

Я бы рекомендовал использовать JS-оболочку (решение 1) в ответе пользователя «ug_». Если вам нужно звонить из Java, вы можете использовать API, экспортированный из пакета jdk.nashorn.api.scripting.

Если «двигатель» — это ваш 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-скрипт может вызвать «getDate()» для вашего объекта API и получить объект JS Date. Обратите внимание, что вы также можете передать аргументы конструктора вызову метода newObject (это вариативный метод Java).

person A. Sundararajan    schedule 14.10.2015