Как я могу сохранить GWT от попытки включать каждый сериализуемый класс, когда я использую ArrayList

У меня есть сервис RPC в GWT, который должен возвратить Список. Список может быть заполнен различными типами объектов, все из которых являются сериализуемыми и на весь из ссылаются в другом месте в моем сервисе, таким образом, они должны быть доступны RPC GWT. Однако, если я не поставил универсальный параметр типа (например. ArrayList<String>), GWT дает мне предупреждение:

Return type: java.util.ArrayList
    java.util.ArrayList
      Verifying instantiability
         java.util.ArrayList
            [WARN] Checking all subtypes of Object which qualify for serialization`
Adding '465' new generated units

По существу я просто хочу способ объявить Список или ArrayList без GWT, пытающегося сгенерировать код для каждого сериализуемого объекта на пути к классу. Разве там некоторый путь не состоит в том, чтобы сказать GWT, что я знаю то, что я делаю а не сходить с ума?

11
задан Robert Munteanu 5 February 2010 в 22:02
поделиться

4 ответа

Позвольте мне подробнее рассказать о том, что сказал Дэвид Ноулс. Компилятор GWT не может читать ваши мысли, поэтому, когда вы не указываете, какими могут быть типы возврата, GWT предполагает, что это может быть что угодно, и должен сделать дополнительную работу, чтобы убедиться, что это может произойти на клиентской стороне Javascript.

Вы действительно должны указать, какие типы возврата могут быть. В этом есть только положительная сторона - компилятор будет производить более оптимизированный код, а не генерировать код для работы с единицами '465 genreated units', так что загрузка будет более быстрой.

Я бы предложил создать пустой интерфейс под названием "BaseResult", а затем, чтобы все возвращаемые объекты реализовали этот интерфейс.

/**
 * Marker interface 
 */
public interface BaseResult {
}

Затем вы указываете, что типом возвращаемого rpc-метода является ArrayList:

public interface MyRpcService extends RemoteService {
  public ArrayList<BaseResult> doRpc();
}

Затем убедитесь, что все возвращаемые объекты реализуют этот интерфейс.

public class UserInfo implements BaseResult {}
public class Order implements BaseResult {}

Теперь компилятору GWT гораздо проще оптимизировать свой код.

5
ответ дан 3 December 2019 в 08:55
поделиться

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

Произошла вторая ошибка, поскольку класс не был инициализирован во время вызова A.getId (). Первая инициализация прервана. Обнаружение этой ошибки было хорошим тестом для инженерной команды; -)

Перспективным подходом для обнаружения такой ошибки является инициализация класса в тестовой среде и отладка кода инициализации (отдельных шагов). Тогда можно будет найти причину проблемы.

-121--3219304-

Вот функция, преобразующая объект в плоский хэш

function flatten(json){
    var nj = {},
        walk = function(j){
            var jp;
            for(var prop in j){
                jp = j[prop];
                if(jp.toString() === "[object Object]"){
                    walk(jp);
                }else{
                    nj[prop] = jp;
                }
            }
        };
    walk(json);
    return nj;
}
-121--4407429-

При добавлении поля ArrayList или Object в сериализуемый объект компилятор GWT не имеет выбора, кроме как включать все возможные Вы, по сути, объявляете Я могу отправить что угодно с помощью этого поля , поэтому компилятор проверяет, что вы можете отправить что-либо.

Решение состоит в объявлении, используя общие параметры, конкретных типов, которые вы отправляете. Для этого может потребоваться разделение на несколько параметров или классов, однако размер кода и время компиляции сохраняются.

3
ответ дан 3 December 2019 в 08:55
поделиться

Вам нужно будет помочь GWT, очень точно сообщив, что вы возвращаете. Типичное решение - использовать корневой класс или интерфейс маркера и объявить, что метод RPC возвращает ArrayList, после чего GWT может сократить возможные типы.

1
ответ дан 3 December 2019 в 08:55
поделиться

Меньше, чем желательно, иметь сериализаторы типов сборки компилятора GWT для всего, что находится под солнцем; в худшем случае это полностью выйдет из строя, потому что, например, может существовать класс (из, скажем, сторонней библиотеки GWT, которую вы используете), который объявляет тип в «клиентском» пакете, который реализует java.io.Serializable . Если вы попытаетесь использовать этот тип в своем коде, он станет частью пути к классам, который компилятор GWT анализирует для создания сериализатора типов; однако во время выполнения класс не является частью пути к классам на сервере, потому что тип был определен в «клиентском» пакете и, следовательно, не скомпилирован для сервера! Вызовы RPC, независимо от того, пытаются они использовать этот конкретный тип или нет, завершаются ошибкой с исключением ClassNotFound. Идеально!

Также, как сформулировано в плакате, невозможно заставить существующие примитивные типы реализовать некоторый интерфейс маркера, будь то IsSerializable или пользовательский интерфейс маркера (например, BaseResult, как предложено выше).

Тем не менее решение необходимо! Итак, вот что я придумал: 1) Используйте IsSerializable (или какой-либо его подкласс) вместо использования java.io.Serializable для всех ваших настраиваемых объектов передачи.

2) Используйте следующую реализацию RpcObject в тех случаях, когда вам нужен общий тип объекта для хранения значения, которое, как вы знаете, будет сериализуемым GWT-RPC (будь то один из ваших настраиваемых объектов передачи, реализующий IsSerializable, или другое "примитивный" тип, такой как java.lang.String [см. комментарии в реализации RpcObject ниже для тех типов, которые были внесены в белый список], который GWT уже знает, как сериализовать!)

Это решение работает для меня ... оно оба не позволяют GWT создавать сериализаторы типов для каждого класса java.io.Serializable под солнцем, в то же время позволяя мне как разработчику передавать значения, используя единый / унифицированный тип для примитивов (что я не могу добавить IsSerializable маркер в), а также мои собственные объекты передачи IsSerializable. Вот пример использования RpcObject (хотя использовать его так просто, мне кажется немного странным включать такие примеры):

RpcObject rpcObject = new RpcObject();
rpcObject.setValue("This is a test string");

Благодаря уловке java-generics метода getValue () приведение типов можно свести к минимуму , поэтому для получения значения (будь то на клиенте или на сервере) вы можете просто сделать следующее без какого-либо преобразования:

String value = rpcObject.getValue();

Вы можете так же легко передать один из ваших настраиваемых типов IsSerializable:

CustomDTO customDto= new CustomDTO(); // CustomDTO implements IsSerializable
customDto.setYourProperty(to_some_value);
RpcObject rpcObject = new RpcObject();
rpcObject.setValue(customDto);

И снова, позже на клиенте или сервере значение может быть легко извлечено (без преобразования):

CustomDTO customDto = rpcObject.getValue();

Вы можете так же легко обернуть что-нибудь вроде java.util.ArrayList:

List list = new ArrayList();  // Notice: no generics parameterization needed!
list.add("This is a string");
list.add(10);
list.add(new CustomDTO());

RpcObject rpcObject = new RpcObject();
rpcObject.setValue(list);

И снова, позже, в клиентском или серверном коде, вы можете вернуть список с помощью:

List list = rpcObject.getValue();

Посмотрев на «белый список» в RpcObject, вы можете быть склонны думать, что только Список попал бы в белый список; вы ошибаетесь ;-) Пока все значения, добавленные в список List , являются IsSerializable или объектами типов из JRE, которые GWT-RPC просто знает , как сериализовать, тогда вы все будет готово. Однако, если вам действительно нужно внести в белый список дополнительные типы, например тип из сторонней библиотеки, в которой используется java.io.Serializable вместо IsSerializable, может потребоваться индивидуальный белый список (подробности см. В реализации RpcObject) , они могут быть добавлены как новые поля непосредственно в RpcObject или, чтобы снизить накладные расходы в общих случаях, добавить их в подкласс RpcObject и использовать подкласс только при необходимости (поскольку это подкласс, ни один из ваших клиентов или серверов сигнатуры методов необходимо изменить с использования универсального типа RpcObject).

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

-Джефф

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.google.gwt.user.client.rpc.IsSerializable;

public class RpcObject implements IsSerializable {
    protected HashMap<String, IsSerializable> rpcObjectWrapper = new HashMap<String, IsSerializable>();

    /*
     * NOTE: The following fields are here to
     * trick/fool/work-around/whatever-you-want-to-call-it GWT-RPC's
     * serialization policy. Having these types present, even though their
     * corresponding fields are never used directly, enables GWT-RPC to
     * serialize/deserialize these primitive types if they are encountered in
     * the rpcWrapperObject! Of course GWT-RPC already knows how to serialize
     * all these primitive types, but since, for example, String doesn't
     * implement GWT's IsSerializable interface, GWT has no expectation that it
     * should ever be allowed in the rpcWrapperObject instance (and thus String,
     * as well as all the other Java primitives plus Arrays of such types as
     * well as List, Set, and Map, won't be part of the serialization policy of
     * the RpcObject type). This is unfortunate because thanks to java type
     * erasure, we can easily stuff Strings, Integers, etc into the wrapper
     * without any issues; however, GWT-RPC will cowardly refuse to serialize
     * them. Thankfully, it appears that the serialization policy is for the
     * RpcObject type as a whole rather than for the rpcObjectWrapper field
     * specifically. So, if we just add some dummy fields with these "primitive"
     * types they will get added to the serialization policy (they are
     * effectively white-listed) of the type as a whole, and alas, GWT-RPC stops
     * cowardly refusing to serialize them.
     */
    protected Byte _byte;
    protected Short _short;
    protected Integer _integer;
    protected Long _long;
    protected Float _float;
    protected Double _double;
    protected Date _date;
    protected Boolean _boolean;

    protected Byte[] _bytes;
    protected Short[] _shorts;
    protected Integer[] _integers;
    protected Long[] _longs;
    protected Float[] _floats;
    protected Double[] _doubles;
    protected Date[] _dates;
    protected Boolean[] _booleans;

    protected List<String> _list;
    protected Set<String> _set;
    protected Map<String, String> _map;

    public RpcObject() {
        super();
    }

    @SuppressWarnings("unchecked")
    public <X> X getValue() {
        HashMap h = (HashMap) rpcObjectWrapper;
        X value = (X) h.get("value");
        return value;
    }

    @SuppressWarnings("unchecked")
    public void setValue(Object value) {
        HashMap h = (HashMap) rpcObjectWrapper;
        h.put("value", value);
    }
}
4
ответ дан 3 December 2019 в 08:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: