Менее желательно иметь сериализаторы типа сборки компилятора GWT для всего под солнцем; в худшем случае он полностью завершается сбоем, потому что, например, может существовать класс (например, используемая вами сторонняя библиотека GWT), который объявляет тип в пакете "client", который реализует java.io.Serializable. , Если вы попытаетесь использовать этот тип в своем коде, он станет частью пути к классам, который анализирует компилятор GWT для создания сериализатора типов; однако в время выполнения класс не является частью пути к классам на сервере, так как тип был определен в пакете "client" и поэтому не скомпилирован для сервера! Вызовы 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, вы можете склониться к мысли, что only List<String>
был бы в белом списке; вы были бы неправы ;-) Пока все значения, добавленные к 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);
}
}