Stringify JSON из GWT ArrayList и возврат в массив - PullRequest
0 голосов
/ 07 февраля 2019

В настоящее время пытаюсь структурировать объект 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 ": [" first ","second "]}"

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

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

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

Я пытался использовать код JSNI для извлечения элементов массива, который на самом деле в консольном трее в веб-браузере работает отлично, но компилятор пытается перехитрить меня и переименовывает элемент array такмой код 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.Массив больше не связан с данными, к которым я пытаюсь получить доступ.

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

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

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

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

1 Ответ

0 голосов
/ 07 февраля 2019

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())));

console ouput «Список» содержит запутанную переменную array_8_g$, это может измениться, поэтому вам никогда не придетсяиспользуйте этот вид кодирования.Результат array в порядке, но вы должны заметить, что он содержит различные свойства (typemarker, casteableTypeMap и __clazz), эти дополнительные свойства используются для выполнения преобразования java, но не перечисляются, поэтому не включаются в следующий результат stringify.Этот результат stringify может быть проанализирован как String[], но теперь результат в parse не включает свойства маркеров типов tye.Таким образом, если вы немедленно сохраните результат 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.

...