如何反序列化对象,如果它被移动到另一个包或重命名?

考虑以下情况:

有一个序列化文件,由旧版本的应用程序创build。 不幸的是,这个包已经改变了,已经被序列化了。 现在我需要从这个文件加载信息到同一个类,但是位于不同的包中。 这个类已经定义了serialVersionUID ,并没有改变(即兼容)。

问题:是否有可能使用任何技巧从这个文件中加载新的类实例(除了将类复制到旧包,然后使用反序列化包装逻辑)? 有可能使用readResolve()来移动/重命名类的恢复? 如果没有,请解释原因。

问题:是否有可能使用任何技巧从这个文件中加载新的类实例(除了将类复制到旧包,然后使用反序列化包装逻辑)?

我不认为你可以使用任何其他的“技巧”,至less不涉及序列化协议的部分重新实现。

有可能使用readResolve()来移动/重命名类的恢复? 如果没有,请解释原因。

不,因为反序列化机制会在更早的时候失败,在试图find被反序列化的类的阶段 – 无法知道另一个包中的类有它应该使用的readResolve()方法。

有可能的:

 class HackedObjectInputStream extends ObjectInputStream { public HackedObjectInputStream(InputStream in) throws IOException { super(in); } @Override protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException { ObjectStreamClass resultClassDescriptor = super.readClassDescriptor(); if (resultClassDescriptor.getName().equals("oldpackage.Clazz")) resultClassDescriptor = ObjectStreamClass.lookup(newpackage.Clazz.class); return resultClassDescriptor; } } 

这还允许忽略serialVersionUIDs不匹配,或者如果字段结构发生更改,则可以反序列化类。

也许你最好的办法是重新创build旧的类(名称,包和序列号),读取序列化的forms,然后将数据复制到新对象的一个​​实例,并重新将其串行化。

如果你有很多这些序列化的对象,也许你可以写一个小脚本来做到这一点,所以“模式更改”一次完成。

另一个select是复活旧类并实现其readResolve方法以返回新类的实例(可能通过声明复制构造函数)。 就我个人而言,我想我会去模式更改脚本,然后删除旧的类为好。

如果您使用天鹅座hex编辑器,您可以手动更改包/类的名称。

如果新名称(总是包括包)具有相同的大小,则可以用新名称replace旧名称,但是如果大小已更改,则需要使用新的新长度更新名称前面的前两个字符。

右键单击标准数据types并更改为Big Endian。

长度是签字。

例如:

 00 0E 70 61 63 6B 61 67 65 2E 53 61 6D 70 6C 65 . . package . S ample 

package.Sample是如何写的。 00 0E表示14,字符数“package.Sample”。

如果我们想更改为newpackage.Sample,我们将该stringreplace为:

 00 12 6E 65 77 70 61 63 6B 61 67 65 2E 53 61 6D 70 6C 65 . . newpackage . S ample 

00 12表示18,字符数为“newpackage.Sample”。

当然你可以让修补程序自动更新它。

我不认为有可能做你想做的事情。

序列化文件的格式保持类名称。 详细来说它有下一个结构:

AC ED

协议版本号

对象数据

对象的类描述

类描述有下一个格式:

全class的名字

串行版本唯一ID(来自字段和方法签名的SHA1)

序列化选项

字段描述符

当你试图反序列化对象的序列化机制时,先比较类名(而你不通过这个步骤),然后它比较serialVersionUID的,只有在通过这2个步骤反序列化对象之后。