更新5月20日:我应该提到有问题的对象确实设置了"serialVersionUID"(旧的和新的都是相同的值),但是在调用readObject()之前序列化失败,但有以下异常:
Exception in thread "main" java.io.InvalidClassException: TestData; incompatible types for field number
我现在还在下面列举一个例子.
我正在使用一个大型应用程序,它从客户端到服务器发送序列化对象(实现Serializable,而不是Exernalizable).不幸的是,我们现在的情况是现有字段完全改变了类型,这打破了序列化.
计划是首先升级服务器端.从那里,我可以控制序列化对象的新版本,以及ObjectInputStream来读取来自客户端的(最初的旧)对象.
我起初想过在新版本中实现readObject(); 然而,在尝试之后,我发现在调用方法之前验证失败(由于不兼容的类型).
如果我是ObjectInputStream的子类,我可以完成我想要的吗?
更好的是,是否有任何第三方库可以进行任何类型的"魔术"?如果有任何工具/库可以将序列化的对象流转换为类似HashMaps的数组,那将非常有趣......无需自己加载对象.我不确定是否可以这样做(将序列化对象转换为HashMap而不加载对象定义本身),但如果可能的话,我可以设想一个可以转换序列化对象(或对象流)的工具)到一个新版本,使用一组属性转换提示/规则等...
谢谢你的任何建议.
5月20日更新 - 下面的示例源 - TestData中的字段'number'从旧版本中的'int'更改为新版本中的'Long'.注意在新版本的TestData中没有调用readObject(),因为在它到达之前会抛出异常:
线程"main"中的异常java.io.InvalidClassException:TestData; 字段编号不兼容的类型
以下是来源.将其保存到文件夹,然后创建子文件夹"旧"和"新".将TestData类的"旧"版本放在"old"文件夹中,将新版本放在"new"中.将"WriteIt"和"ReadIt"类放在main(旧/新的)父文件夹中.'cd'到'old'文件夹,并使用:javac -g -classpath . TestData.java
... 编译, 然后在'new'文件夹中执行相同的操作.'cd'回到父文件夹,并编译WriteIt/ReadIt:
javac -g -classpath .;old WriteIt.java
javac -g -classpath .;new ReadIt.java
Run Code Online (Sandbox Code Playgroud)
然后运行:
java -classpath .;old WriteIt //Serialize old version of TestData to TestData_old.ser
java -classpath .;new ReadIt //Attempt to read back the old object using reference to new version
Run Code Online (Sandbox Code Playgroud)
[旧版本] TestData.java
import java.io.*;
public class …Run Code Online (Sandbox Code Playgroud)