让 GWT 编译器为阳光下的所有东西构建类型序列化器是不可取的;在最坏的情况下,它会完全失败,因为例如,可能有一个类(假设是您正在使用的第三方 GWT 库)在实现 java.io.Serializable 的“客户端”包中声明了一个类型. 如果您尝试在代码中使用该类型,它将成为 GWT 编译器分析以构建类型序列化程序的类路径的一部分;但是,在运行时,该类不是服务器上类路径的一部分,因为该类型是在“客户端”包中定义的,因此不是为服务器编译的!RPC 调用,无论它们是否尝试使用该特定类型,都会失败并出现 ClassNotFound 异常。完美的!
正如海报所阐明的那样,不可能使现有的原始类型实现一些标记接口,无论它是 IsSerializable 还是自定义标记接口(例如上面建议的 BaseResult)。
尽管如此,还是需要一个解决方案!所以这就是我想出的:1)使用 IsSerializable(或它的某个子类)而不是在所有自定义传输对象上使用 java.io.Serializable。
2) 在您需要通用对象类型来保存您知道将是 GWT-RPC 可序列化的值的那些实例中使用以下 RpcObject 实现(无论它是实现 IsSerializable 或更“原始”的自定义传输对象之一GWT 已经知道如何序列化的类型,例如 java.lang.String [有关已列入白名单的类型,请参阅下面 RpcObject 实现中的注释]!)
这个解决方案对我有用......它既可以防止 GWT 为阳光下的每个 java.io.Serializable 类构建类型序列化器,同时又允许我作为开发人员使用单一/统一类型来传输值基元(我无法添加 IsSerializable 标记接口)以及我自己的自定义 IsSerializable 传输对象。下面是一个使用 RpcObject 的例子(虽然使用起来很简单,但是包含这样的例子我感觉有点奇怪):
RpcObject rpcObject = new RpcObject();
rpcObject.setValue("This is a test string");
由于 getValue() 方法的 java-generics 技巧,可以将强制转换保持在最低限度,因此要检索值(无论是在客户端还是服务器上),您只需执行以下操作而无需投掷:
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<String>
被列入白名单;你会错的 ;-) 只要添加到的所有值都是 IsSerializable 或 GWT-RPC只知道List
的 JRE 类型的对象如何序列化,然后你就准备好了。但是,如果您确实需要将其他类型列入白名单,例如使用 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);
}
}