RMI和普通对象序列化之间有区别吗?

时间:2014-07-17 12:28:16

标签: java object serialization deserialization rmi

对我来说似乎有点奇怪。我有两个类通过RMI进行通信。如果我在生产系统上使用RMI传输对象图,那么在目标处会丢失一些数据。

为了更深入地分析,我将对象图序列化到光盘,然后通过RMI将其返回给调用者。在调用者方面,我也将返回的对象写入光盘。两个文件的大小不同。

使用小助手将它们传回给对象图我认识到在将数据传输到呼叫者旁边的呼叫者后,某些对象丢失了。

老实说,我发现这很奇怪,我不知道发生了什么。因为同样的事情在我的开发者机器上工作。我期待一个SerializationException,但没有抛出。

我迷路了;-(。我希望如果光盘上的对象序列化工作也适用于RMI。

有谁知道调试此行为的第一步?

1 个答案:

答案 0 :(得分:3)

你的一条评论中包含一条重要线索,这些线索让我对可能发生的事情进行假设。如果不同系统上的类确实不同,那么有些方法可能会有所不同,因此序列化和反序列化可能导致信息丢失,并且不会报告异常或错误。

对于没有错误,双方必须具有相同的可序列化类(按名称),如果这些类不同,则必须声明相同的serialVersionUID值。如果添加或删除了可序列化数据字段,则可能导致数据被丢弃而不会出现错误。如果没有实现自定义可序列化表单(readObjectwriteObject方法),这很容易发生,但即使实现了这些方法并且在进化过程中没有采取适当的谨慎措施,它仍然可能发生。类。

这是一个例子。假设有一个类A最初定义如下:

// original version
class A implements Serializable {
    private static final long serialVersionUID = 9783425L;
    String x;
    String y;
}

现在让我们说在下一个版本中,该类中添加了另一个字段:

// modified version
class A implements Serializable {
    private static final long serialVersionUID = 9783425L;
    String x;
    String y;
    String z;
}

现在假设一台机器具有类A的修改版本,并且已经序列化了该类的一些实例。它现在将此序列化数据(通过RMI或通过其他方式实际上并不重要)传输到恰好具有类A的原始版本的另一台机器。当这台机器反序列化A的实例时,新字段z中的序列化数据将被静默删除!

当朝另一个方向走时,会发生相反的排序。如果具有原始版本A的机器将序列化数据传输到具有新版本的机器,则在反序列化时,将不会有新类型的z字段的数据,因此{ {1}}字段将保留其默认值,即null。

Section 3.1 of the Serialization Specification中对此进行了描述,其中讨论了z方法:

  

对象中未出现在流中的任何字段都将设置为其默认值。显示在流中但不在对象中的值将被丢弃。这种情况主要发生在类的更高版本编写了在早期版本中未出现的其他字段时。

我认为这不是序列化数据在系统之间可能存在差异的唯一可能方式,但如果类别不同,那么这可能是正在发生的事情。

如何调试?由于您已将序列化字节写入磁盘并且它们不同,因此您可以选择编码的序列化表单并查看差异。序列化数据格式并不复杂,但它非常繁琐。

另一种方法是使用defaultReadObject检查不同系统上的类。您需要javap -private,因为即使是私有字段也可以序列化。这可能会告诉您是否在不同系统上的不同版本之间添加或删除了任何字段。