我在GWT中定义了一个简单的“键值存储”服务;我将编写服务器,但让其他人编写客户端,因此它应该尽可能简单。我希望客户端能够使用String键,但任何可序列化类型的值。所以我定义了界面:
public void put(String key, java.io.Serializable value);
public java.io.Serializable get(String key);
这很有效,但有一个问题:Eclipse对这两种方法都给出了以下警告:
检查符合序列化条件的Object的所有子类型
谷歌搜索该警告,似乎GWT将为程序中的每一种类型生成一段代码。因此,这可能非常昂贵。我很困惑,因为我认为Serializable接口中的所有类型都已经有序列化代码,它可以调用它(但可能只是在这种情况下生成序列化代码)。
所以我有很多问题:
IsSerializable
。我可以用它吗?我尝试了但是我注意到像String和Integer这样的基本类没有实现这个接口。byte[]
,但为我的客户提供了一个包装器方法,以便将java.io.Serializable
序列化为byte[]
,这样可以解决问题,还是会最终我遇到了与我开始时相同的代码膨胀问题?答案 0 :(得分:2)
我看到GWT提供了一个单独的接口IsSerializable。我可以用它吗?我试了但是我注意到像String和Integer这样的基本类没有实现这个接口。
是。 IsSerializable优于java.io.Serializable。 GWT FAQ列出了原因:
- GWT序列化的语义远比标准Java序列化复杂,因此使用java.io.Serializable作为标记接口意味着GWT的序列化系统能够实现比实际更多的能力。
- 相反,GWT的序列化机制比标准Java更简单,因此使用java.io.Serializable意味着用户比实际更需要担心(例如序列化版本ID)。
- GWT仅实现完整Java JRE类的一部分,并且在java.io中没有特别实现。使用java.io.Serializable作为GWT RPC序列化标记接口会稀释java.io在GWT应用程序中不可用的消息。
>
如果我使RPC层使用byte [],但是为我的客户端提供了一个包装器方法来将java.io.Serializable序列化为byte [],那么它会解决问题,还是会以我开始使用相同的代码膨胀问题?
糟糕的主意。在这种情况下,从对象到byte []的序列化将在客户端的JavaScript中进行。是的,可以在客户端进行序列化,但使用GWT协议;这不是Java序列化。浏览器不会那么好。
有没有更好的方法来实现一个键值存储,它允许任意类型的值而不代表客户端进行太多工作?
不幸的是,我认为你无法逃脱所有课程的真正方法。我建议你尝试以下界面:
interface Store<T extends Serializable & IsSerializable> {
void put(String key, String value);
void put(String key, Number value);
void put(String key, T value);
Integer getInt(String key);
Double getDouble(String key);
BigDecimal getBigDecimal(String key);
String getString(String key);
IsSerializable get(String key);
}
泛型确保对象具有两个接口,因此您可以使用GWT协议(从客户端到服务器)和Java序列化(从服务器到数据存储)进行序列化。
修改回复评论:
使用最后一个解决方案,通用意味着商店只能存储单一类型的对象,如果客户想要存储不同的对象,他必须创建一个新商店吗?
是的,客户端必须为每种类型创建一个新商店。如果它真的困扰你,解决这个问题的方法是创建一个新的接口MySerializable,它扩展了IsSerializable和java.io.Serializable;但是每个对象都必须实现它,这会对你的项目产生依赖。
也不要求对象是Serializable和IsSerializable吗?
是的,这是一个好处。否则,您可能会在服务器端拥有一个不是java.io.Serializable的对象;如果你试图将它提供给方法ObjectOutputStream#writeObject,那么你的脸上就会出现例外情况。
最后,我的第一个问题是:只是使用io.Serializable实际上会影响代码大小/性能吗?
我不能说从实际用途,但我不这么认为:两者都只是标记接口。两者的GWT序列化都是相同的。