Как преобразовать массивы Rhino-JavaScript в Java-массивы

У меня есть следующее:

ScriptEngineManager mgr = new ScriptEngineManager();
ScriptEngine jsEngine = mgr.getEngineByName("JavaScript");
jsEngine.eval("function getArray() {return [1,2,3,4,5];};");
Object result = jsEngine.eval("getArray();");

Как я могу преобразовать объект результата, который имеет тип sun.org.mozilla.javascript.internal.NativeArray в соответствующий массив Java? Может ли кто-нибудь показать мне пример рабочего кода, где это делается? Должно работать для массивов String и Integer. Кроме того, было бы здорово узнать, где искать другие преобразования типов данных между движком rhino и java.

Кстати, я знаю эту страницу, но я действительно ищу пример рабочего кода.

4 ответа

Решение
NativeArray arr = (NativeArray) result;
Object [] array = new Object[(int) arr.getLength()];
for (Object o : arr.getIds()) {
    int index = (Integer) o;
    array[index] = arr.get(index, null);
}

Я не уверен, что это был тот случай, когда этот вопрос был впервые задан, но NativeArray реализует java.util.List интерфейс. Поэтому простой способ преобразования в настоящий массив Java:

Object[] array = ((List<?>) result).toArray();

Если Javascript находится под вашим контролем, вы можете выполнить там преобразование согласно этому документу. Итак, чтобы адаптировать ваш пример, что-то вроде:

ScriptEngineManager mgr = new ScriptEngineManager();
ScriptEngine jsEngine = mgr.getEngineByName("JavaScript");
jsEngine.eval("function getArray() {return [1,2,3,4,5];};");
String convertFuncSrc =
     "function convertArray(type, arr) {"
   + "  var jArr = java.lang.reflect.Array.newInstance(type, arr.length);"
   + "  for (var i = 0; i < arr.length; i++) { "
   + "    jArr[i] = arr[i];"
   + "  }"
   + "  return jArr;"
   + "};";
jsEngine.eval(convertFuncSrc);
Object result = jsEngine.eval("convertArray(java.lang.Integer.TYPE, getArray());");
int[] javaArray = (int[])result;

Хотя, если вы не можете изменить Javascript, этот подход не будет работать, и у вас [i] будет [/i] экземпляр sun.org.mozilla.javascript.internal.NativeArray в качестве вашего result переменная. В этот момент я думаю, что вам просто нужно разыграть и разобраться с ним напрямую, используя любые открытые методы, которые он выставляет; это, вероятно, не красиво, но я не вижу других вариантов. В частности, я думаю, что единственное, что вы можете гарантировать на хорошем уровне Rhino, это то, что он будет примером Scriptable (и, вероятно, ScriptableObject), что не поможет вам использовать его в качестве массива.

Ответ Кевина выглядит как хороший способ пойти сюда (и похож на то, что я только что собирался редактировать!:-))

В моем случае я хотел создать массив Java внутри сценария. (Этот вариант использования также соответствует вопросу.)

После создания массивов Java я придумал

var javaArray = java.lang.reflect.Array.newInstance(java.lang.Integer, jsArray.length);
for (var i = 0; i < javaArray.length; i++) {
  javaArray[i] = new java.lang.Integer(jsArray[i]);
}

Общее решение с использованием JASON в качестве промежуточного звена данных:

Object result = jsEngine.eval("JSON.stringify(getArray())");    
JsonReader jsonReader = Json.createReader(new StringReader(result.toString()));
JsonArray jsonArray = jsonReader.readArray();
jsonReader.close();
int[] numbers = new int[jsonArray.size()];
int index = 0;
for(JsonValue value : jsonArray){
    numbers[index++] = Integer.parseInt(value.toString());
}
Другие вопросы по тегам