Stringify JSON из GWT ArrayList и возврат в массив

В настоящее время пытаюсь структурировать объект Java ArrayList в GWT, используя метод взаимодействия для вызова собственного JSON.stringify(ArrayListobj). Это приводит к прекрасному представлению JSON базового содержимого списка массивов в форме массива. Это даже работает для, казалось бы, более сложных объектов класса Java, но в этом случае я собираюсь использовать Strings для демонстрации. Сначала на моей стороне создания:

test = new ArrayList<>();
test.add("first");
test.add("second");
String jsonstr = JSON.stringify(test);

Теперь, основываясь на моем коде JsInterop, я возвращаю объект (или массив объектов, как в следующем коде, показанном здесь):

@JsType(isNative=true, namespace=GLOBAL)
public class JSON {
  public native static String stringify(Object obj);
  public native static Object[] parse(String obj);
}

Пока все хорошо, все это работает отлично, и результаты, которые я получаю, представляют собой строковое представление JSON содержимого ArrayList.

"{"array_0":[" первый " "второй"]}"

Затем запустите этот бит через парсер:

ArrayList<String> returned = new ArrayList<>();
Object[] var = JSON.parse(jsonstr);

И var - это правильное представление (при остановке выполнения веб-браузера) базовых данных из первого ArrayList. Проблема в том, что Object[] массива JSON преобразован обратно в объект Java ArrayList.

Я пытался использовать код JSNI для извлечения элементов массива, который на самом деле в консольном трее в веб-браузере работает отлично, но компилятор пытается перехитрить меня и переименовывает элемент массива, чтобы мой код JSNI не мог его коснуться.

Если мой код, как указано выше, и я пишу JSNI что-то вроде:

    public static native ArrayList objToList(ArrayList add,Object inVal) /*-{
         var length = inVal.array.length;
         for(var i = 0;i < length; i++){
             add.array[i] = inVal.array[i];
         }
         return add;
     }-*/;

Затем компилятор переименует массив array_0, так что мой код, который говорит inVal.array, больше не связан с данными, к которым я пытаюсь получить доступ.

Из всех проведенных мною испытаний это, безусловно, самый быстрый метод получения одного и того же объекта ArrayList (его гарантированное одинаковое определение в обоих местах) из одного места в клиентском программном обеспечении в другое место в клиентском программном обеспечении (без сервера). участвует здесь) через строковое.

Но информация о том, как манипулировать JavaScript на низком уровне в GWT, в лучшем случае отсутствует.

И я попробовал все варианты механизмов GWT-RPC, GWT-Джексона, AutoBeans (если только они поддерживали объекты с несколькими типами примитивов!), Вы называете это.

И НЕТ, прежде чем вы это предложите, я не заинтересован в том, чтобы снова выполнить полный анализ строки GWT-JSON, я уже сделал это, когда первоначально извлекал тысячи записей с сервера и помещал их в Java ArrayList. Для анализа JSON в GWT требуется более 200 мс, а функция анализа JSON в браузерах обрабатывает эту строку примерно за 3 мс.

1 ответ

GWT использует маркеры типов для отслеживания типов и обеспечения безопасности приведения классов. Вы никогда не должны использовать stringify с классами Java, потому что вы потеряете эти маркеры типов, а также будете использовать внутренние свернутые / закодированные символы. Итак, вот как GWT внутренне обрабатывает все эти типы:

List<String> list = new ArrayList<>();
list.add("a"); list.add("b");
console.log("list", list);
console.log("array", list.toArray());
console.log("stringify", Global.JSON.stringify(list.toArray()));
console.log("parse", Global.JSON.parse(Global.JSON.stringify(list.toArray())));

"Список" содержит запутанную переменную array_8_g$ это может измениться, поэтому вам никогда не следует использовать этот вид кодирования. array результат в порядке, но вы должны заметить, что он содержит различные свойства (typemarker, casteableTypeMap и __clazz), эти дополнительные свойства используются для выполнения приведения типов в Java, но не перечисляются, поэтому не включаются в следующий результат stringify, это stringify результат может быть проанализирован как String[], но теперь результат в parse не включены свойства маркеров типов. Итак, если вы сразу же сохраните результат parse в String[] переменная, она будет работать правильно. Но если вы бросите это как Object и попытаться бросить его обратно String[] это не удастся.

В зависимости от jsinterop: base есть 2 утилиты Js # cast и Js # uncheckedCast, которые полезны в этих случаях. Если в массиве есть маркер типа, вы можете использовать Js # cast (эта утилита такая же, как и в обычном java-кастинге), если нет, вы должны использовать Js # uncheckedCast.

В этом примере первая строка будет успешной, а вторая - с исключением приведения класса:

console.log("uncheck", Js.<String[]>uncheckedCast(JSON.parse(JSON.stringify(list.toArray())))[0]);
console.log("check", Js.<String[]>cast(JSON.parse(JSON.stringify(list.toArray())))[0]);

Вы действительно должны стараться не смешивать нативный код JS с Java. Если вам нужно сделать это, то вы должны понять внутреннее устройство того, как GWT обрабатывает типы, вы должны понимать JSNI, но использовать его как можно меньше и, наконец, понять, как работает JsInterop, и использовать его для доступа к собственному JS-коду или предоставления кода Java. в мир JS.

Другие вопросы по тегам