【发布时间】:2014-01-03 22:51:11
【问题描述】:
背景
我正在尝试以这样一种方式编写对象反序列化:如果对象数组包含 一些 对象(由于代码更改)无法反序列化,那么数组中的那些引用将变为 null 而不是抛出异常;允许回收对象的其余部分。
我尝试过的
我尝试使用自定义序列化/反序列化,希望能够捕获异常并应用我的自定义“使其为空”逻辑。代码如下。然而,我似乎能够捕捉到异常的第一点是整个数组反序列化已经失败。
public class AppleHolder implements Serializable{
Apple[] apples=new Apple[5];
double otherData=15;
public AppleHolder(){
Apple goodApple=new Apple("GoodApple","tastyGood");
BadApple badApple=new BadApple("BadApple","tastyBad");
apples[0]=goodApple;
apples[1]=goodApple; // multiple references to same object intentional
apples[2]=goodApple;
apples[3]=badApple;
apples[4]=badApple;
}
private void writeObject(ObjectOutputStream o)
throws IOException {
o.writeObject(apples);
o.writeObject(otherData);
}
private void readObject(ObjectInputStream o)
throws IOException, ClassNotFoundException {
apples = (Apple[]) o.readObject();
otherData = (double) o.readObject();
}
public static void main(String[] args)
throws Exception {
/*
* (1) First run serialize()
* (2) Change the badApple's serialVersionUID to 2
* (3) Run deSerialize(()
*/
serialize();
//deSerialize();
}
public static void serialize() throws Exception{
AppleHolder testWrite = new AppleHolder();
FileOutputStream fos = new FileOutputStream("testfile");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(testWrite);
oos.flush();
oos.close();
}
public static void deSerialize() throws Exception{
AppleHolder testRead;
FileInputStream fis = new FileInputStream("testfile");
ObjectInputStream ois = new ObjectInputStream(fis);
testRead = (AppleHolder) ois.readObject();
ois.close();
System.out.println("--Read object--");
System.out.println("propertyOne: " + testRead.apples[0].getPropertyOne());
}
}
public class Apple implements Serializable {
private String propertyOne;
private String propertyTwo;
public Apple(String propertyOne, String propertyTwo) {
this.propertyOne = propertyOne;
this.propertyTwo = propertyTwo;
validate();
}
private void writeObject(ObjectOutputStream o)
throws IOException {
o.writeObject(propertyOne);
o.writeObject(propertyTwo);
}
private void readObject(ObjectInputStream o)
throws IOException, ClassNotFoundException {
propertyOne = (String) o.readObject();
propertyTwo = (String) o.readObject();
validate();
}
private void validate(){
if(propertyOne == null ||
propertyOne.length() == 0 ||
propertyTwo == null ||
propertyTwo.length() == 0){
throw new IllegalArgumentException();
}
}
public String getPropertyOne() {
return propertyOne;
}
public String getPropertyTwo() {
return propertyTwo;
}
}
public class BadApple extends Apple {
private static final long serialVersionUID = 1;
public BadApple(String propertyOne, String propertyTwo) {
super(propertyOne, propertyTwo);
}
}
我的例外是
Exception in thread "main" java.io.InvalidClassException: customserialisation.BadApple; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:617)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1620)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1515)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1769)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1348)
at java.io.ObjectInputStream.readArray(ObjectInputStream.java:1704)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1342)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370)
at customserialisation.AppleHolder.readObject(AppleHolder.java:43)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1017)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1891)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1796)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1348)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370)
at customserialisation.AppleHolder.deSerialize(AppleHolder.java:79)
at customserialisation.AppleHolder.main(AppleHolder.java:61)
我认为这可以让我通过捕捉异常而不是部分 apples 数组来挽救“otherData”。
我尝试了什么 2
根据 Alexander Torstling 的 answer,我试图从反序列化的片段中重新创建数组
apples=new Apple[appleCount]
for(int i=0; i<appleCount; i++) {
try {
apples[i]= o.readObject());
} catch(Exception e) {
//Add null or nothing or what you want.
apples[i]=null;
}
}
但是,这不会消耗 badApple 可能在其中包含的任何 o.readObject()(在本例中为两个字符串),因为反序列化的数据不同步,在我的情况下,我得到一个强制转换异常,因为otherData = (double) o.readObject(); 读取应该是 BadApple 的一部分的 String,因为它从未从流中消耗。
问题
我怎样才能挽救一个序列化数组,其中只有一些对象是可反序列化的?从而为不可反序列化的部分获得一个包含空条目的数组。在我的数组中,我在一个数组中有多个对同一个对象的引用,必须在反序列化过程中保留这些引用。
所以进入序列化我有
[GoodApple]
[GoodApple]
[GoodApple]
[BadApple]
[BadApple]
我想要从反序列化中出来(因为 badApple 已经改变并且无法反序列化
[GoodApple]
[GoodApple]
[GoodApple]
[null]
[null]
我希望它提供一个后备方案,在无法实现向后兼容性或对我之前安装的程序的第 3 方修改被删除的情况下
【问题讨论】:
-
与此相关的问题,其中使用 Kryo 序列化库(我发现它更快)解决了同样的问题;Deserializing an array that contains some non-deserializable objects using Kryo (salvaging the deserializable parts)
标签: java arrays serialization