GWT-RPC 服务是不是应该使用 java.io.Serializable 作为参数类型?

Posted

技术标签:

【中文标题】GWT-RPC 服务是不是应该使用 java.io.Serializable 作为参数类型?【英文标题】:Should a GWT-RPC service use java.io.Serializable as a parameter type?GWT-RPC 服务是否应该使用 java.io.Serializable 作为参数类型? 【发布时间】:2011-04-04 12:39:42 【问题描述】:

我在 GWT 中定义了一个简单的“键值存储”服务;我将编写服务器,但让其他人编写客户端,所以它应该尽可能简单。我希望客户端能够使用字符串键,但任何可序列化类型的值。于是我定义了接口:

public void put(String key, java.io.Serializable value);
public java.io.Serializable get(String key);

这很好用,但是有一个问题:Eclipse 对这两种方法都给出了以下警告:

检查所有符合序列化条件的 Object 子类型

谷歌搜索该警告,似乎 GWT 将为程序中的每种类型生成一段代码。因此,这可能非常昂贵。我很困惑,因为我认为 Serializable 接口中的所有类型都已经有序列化代码,它可以调用它(但也许只有在这种情况下才会生成序列化代码)。

所以我有几个问题:

这会使客户端代码 a) 更大和/或 b) 更慢吗?这个问题有多严重? 我看到 GWT 提供了一个单独的接口IsSerializable。我可以用那个代替吗?我试过了,但我注意到像 String 和 Integer 这样的基本类没有实现这个接口。 如果我让 RPC 层改用byte[],但为我的客户提供一个包装方法来将java.io.Serializable 序列化为byte[],这会解决问题,还是会以相同的结果结束我开始遇到的代码膨胀问题? 是否有更好的方法来实现键值存储,它允许任意类型的值而不需要代表客户端进行太多工作? 如果我坚持使用 Serializable,有没有办法抑制该警告?

【问题讨论】:

注意:至于抑制该警告,目前似乎没有办法做到这一点。上面有个问题,Issue 3501。 【参考方案1】:

我看到 GWT 提供了一个单独的接口 IsSerializable。我可以用那个代替吗?我试过了,但我注意到像 String 和 Integer 这样的基本类没有实现这个接口。

是的。 IsSerializable 优于 java.io.Serializable。 GWT FAQ 列出了原因:

GWT 序列化的语义远没有标准 Java 序列化那么复杂,因此使用 java.io.Serializable 作为标记接口意味着 GWT 的序列化系统比它实际的能力更强。 em> 相反,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 序列化(从服务器到数据存储)进行序列化。

编辑回答 cmets:

对于最后一个解决方案,通用是不是意味着商店只能存储一种类型的对象,如果客户想要存储不同的对象,他必须创建一个新的商店?

是的,客户必须为每种类型创建一个新商店。如果它真的困扰你,解决这个问题的方法是创建一个新的接口 MySerializable,它扩展了 IsSerializable 和 java.io.Serializable;但是每个对象都必须实现它,这会创建对您的项目的依赖。

是否还要求对象既是可序列化的又是可序列化的?

是的,这是一个好处。否则,您可能会在服务器端有一个不是 java.io.Serializable 的对象;如果您尝试将其提供给方法ObjectOutputStream#writeObject,则会出现异常。

最后,我的第一个问题是什么:仅仅使用 io.Serializable 真的会影响代码大小/性能吗?

我不能从实际使用中这么说,但我不这么认为:两者都只是标记接口。两者的 GWT 序列化都是相同的。

【讨论】:

感谢您的建议。哎呀,看起来没有一个简单的出路。使用最后一个解决方案,通用不是意味着商店只能存储一种类型的对象,如果客户想要存储不同的对象,他必须创建一个新的商店?也不需要对象既是可序列化的又是可序列化的?最后,关于我的第一个问题:仅仅使用 io.Serializable 真的会影响代码大小/性能吗? 感谢您提供额外信息。我想我会冒险,尽管有警告,但还是使用 java.io.Serializable。但是感谢您清楚地解释问题的所有方面。

以上是关于GWT-RPC 服务是不是应该使用 java.io.Serializable 作为参数类型?的主要内容,如果未能解决你的问题,请参考以下文章

GWT-RPC 序列化的 ImmutableCollection 声明

GWT-RPC 和不可变传输对象

gwt-rpc vs rest ......真的是其中之一吗?

将泛型与 GWT-RPC 一起使用未按预期工作

为 Web 和 Android 服务的 AppEngine GWT-RPC 服务

如何使用 HttpClient 发送 GWT-RPC 请求?