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

2022-09-01 01:23:38

请考虑以下情况:

有一个由旧版本的应用程序创建的序列化文件。遗憾的是,该类的包已更改,该类已序列化。现在我需要将此文件中的信息加载到同一类中,但位于不同的包中。此类已定义且未更改(即兼容)。serialVersionUID

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


答案 1

有可能:

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;
    }
}

这也允许人们忽略串行VersionUID不匹配,甚至在类的字段结构发生更改时反序列化类。


答案 2

问:是否可以使用任何技巧从此文件加载新的类实例(除了将类复制到旧包中,然后使用反序列化包装器逻辑的简单操作)?

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

编辑:实际上有一个钩子允许这样做,如果你控制反序列化过程,看到另一个答案。

是否可以使用 readResolve() 从移动/重命名类中恢复?如果没有,请解释原因。

不可以,因为反序列化机制在尝试查找正在反序列化的类的阶段会更早失败 - 它无法知道不同包中的类具有它应该使用的方法。readResolve()