Функция связывания Java и Javascript с массивами в качестве параметра - PullRequest
0 голосов
/ 24 октября 2018

Я пытаюсь добиться следующего.Приложение Java должно запускать javascript через ScriptEngineManager / ScriptEngine, и JavaScript должен иметь возможность вызывать функции из приложения Java.Это прекрасно работает, если только и просто передается простая переменная.Но я не могу заставить его передавать массивы.Вот мой код:

private static class test implements Function<Integer[], Integer[]> {
    @Override
    public Integer[] apply(Integer[] msg) {
        for(int i = 0; i < msg.length; i++) System.out.println(msg[i]);     
        Integer[] a = {1, 2, 3};           
        return a;
    }
}

public static void main(String[] args) throws ScriptException {
    String ps = "var e = [0x04, 0x05, 0x06]; var a = send(e); for(i in a) print(i);";
    ScriptEngineManager sm = new ScriptEngineManager();
    ScriptEngine eng = sm.getEngineByName("JavaScript");
    Bindings mbind = eng.createBindings();
    mbind.put("send", new test());
    eng.setBindings(mbind, ScriptContext.ENGINE_SCOPE);
    Object t = eng.eval(ps);
}

Я получаю ошибку:

Исключение в потоке "main" java.lang.ClassCastException: jdk.nashorn.api.scripting.ScriptObjectMirror не можетбыть приведенным к [Ljava.lang.Integer;при тестировании сценария $ test.apply (scripttest.java:1) на jdk.nashorn.internal.scripts.Script $ \ ^ eval_.:program(:1) на jdk.nashorn.internal.runtime.ScriptFunctionData.invoke (ScriptFunctionData.java): 637) в jdk.nashorn.internal.runtime.ScriptFunction.invoke (ScriptFunction.java:494) в jdk.nashorn.internal.runtime.ScriptRuntime.apply (ScriptRuntime.java:393) в jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl (NashornScriptEngine.java:446) в jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl (NashornScriptEngine.java:403) в jdk.nashorn.api.scripting.NashornScriptIjine.jg (Ng).nashorn.api.scripting.NashornScriptEngine.eval (NashornScriptEngine.java:155) в javax.script.AbstractScriptEngine.eval (неизвестный источник) в scripttest.main (scripttest.java:26)

ЕстьУ кого-нибудь есть идеи о том, как передавать массивы?

Спасибо!Привет

1 Ответ

0 голосов
/ 28 марта 2019

Отражение на массивах - небольшая проблема в Java (примитивные типы и все такое прочее), поэтому у скриптовых движков JSR-223 с ними проблемы.Я пробовал тот же код с новым GraalVM, и это страдает от той же проблемы - движок разочаровывается в поиске хорошего сопоставления и просто пытается представить свое собственное представление значения массива (Nashorn использует ScriptObjectMirror, а GraalVM использует PolyglotMap).

Если вы хотите, чтобы ваша функция хоста выглядела так, как будто она принимает "реальный массив" (реализация гостевого массива), ваша функция хоста должна будет принять внутреннюю базовую ScriptEngineреализации и научиться оперировать этим.Согласно этому SO-ответу и ScriptObjectMirror API документам вы должны иметь возможность использовать метод obj.to(int[].class) для извлечения внутреннего целочисленного массива из прокси-объекта.

Основным недостатком этого подхода является то, что ваша функция хоста должна поддерживать каждое конкретное внутреннее представление каждой конкретной ScriptEngine s, которую вы, возможно, захотите поддерживать.

Поскольку механизм Jashascript Nashorn устарел в текущих JDK, вы можете захотетьдля поддержки GraalVM, в случае чего ваша реализация может выглядеть примерно так:

private static class test implements Function<Object, Integer[]> {
    @Override
    public Integer[] apply(Object inp) {
        int[] msg;
        if (inp instanceof ScriptObjectMirror)
            msg = ((ScriptObjectMirror)inp).to(int[].class);
        else if (inp instanceof AbstractMap)
            msg = Value.asValue(inp).as(int[].class);
        else
            return null;
        for (int i = 0; i < msg.length; i++)
            System.out.println(msg[i]);
        Integer[] a = { 1, 2, 3 };
        return a;
    }
}
...