我想编写代码,即使更改了类,该代码也可以反序列化类(但是您使用的是旧类版本)。
这个想法很简单。
阅读序列化类的serialVersionUID
检查serialVersionUID
是否等于当前类版本的serialVersionUID
。
如果不是,请创建新的ClassLoader
并将旧的类版本加载到工作区中。
我想用这样的东西:
FileInputStream file = new FileInputStream(filename);
ObjectInputStream o = new ObjectInputStream(file) {
protected Class<?> resolveClass(java.io.ObjectStreamClass desc) throws IOException, ClassNotFoundException {
//5639490496474438904L is the suid of the older version
if (desc.getSerialVersionUID() == 5639490496474438904L) {
Class c01 = null;
URL eineURL = new URL("file://localhost/U:/MyJavaProj/bin/test/oldversion/");
URL[] reiURL = new URL[] {eineURL};
URLClassLoader clazLader = new URLClassLoader(reiURL);
c01 = clazLader.loadClass("test.SerObj");
return c01;
}
return super.resolveClass(desc);
}
};
SerObj obj = (SerObj) o.readObject();
问题出在最后一行。我当前的课程版本位于U:/MyJavaProj/bin/test/SerObj.class
我的旧类版本位于U:/MyJavaProj/bin/test/oldversion/test/SerObj.class
在最后一行中,我阅读了旧的类版本,但将其转换为新的版本:(
是否有人对Java的序列化添加了版本控制支持?
最佳答案
您将无法在最后一行执行转换,因为它属于不同的类(不可转换)-您可能会收到诸如test.SerObj is not an instance of test.SerObj
之类的令人困惑的消息。
这是由于一个类本质上是一个java.lang.Class
实例,该实例在给定的类加载器中至关重要,因此是唯一的。即使您引用了完全相同的*.class
文件,默认类加载器加载的SerObj
实例也与SerObj
加载的clazLader
实例是不同的类。任何一个类别都不能转换为另一个类别。
因此,如果您需要使用多个类加载器进行反序列化,则该方法将不可能返回SerObj
。 (此外-当两个类文件可能具有任意差异时,怎么可能?)
一种可能的解决方法是定义一个接口,该接口定义在类的版本之间固定的行为。如果设置临时类加载器,使其只能从oldversion类文件中加载SerObj
,并且具有正确的父类加载器,则旧的SerObj
仍应实现根类加载器定义的接口类。
在这种情况下,新的SerObj
和旧的SerObj
实例都可以转换为SerObjIface
接口,因此您可以声明方法以返回该接口。实际上,如果您希望调用者处理不同而又相似的类(这是“同一类”的不同版本),则可以说应该为此返回一个接口。