gpt4 book ai didi

java - 反序列化包含一些不可反序列化对象的数组(抢救可反序列化部分)

转载 作者:行者123 更新时间:2023-12-01 13:39:57 24 4
gpt4 key购买 nike

背景

我正在尝试以这样的方式编写对象反序列化:如果对象数组包含某些对象(由于代码更改)无法反序列化,那么数组中的那些引用将变为 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)是

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 Torsling 的 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 方修改时提供后备

最佳答案

我不确定我完全理解你的问题,但由于你不想中断数组反序列化,我认为你无法以任何有意义的方式捕获并继续。然后我看到的其他选项是编写自定义数组反序列化例程或为 BadApple 编写自定义反序列化程序。如果向后兼容很困难,那么只需将字段设置为虚假值并设置一个指示“错误条目”的标志怎么样?问题是不能修改BadApple类吗?

编辑:顺便说一句,如果您不想了解数组反序列化是如何完成的,请查看ObjectInputStream#readArray。看起来可以复制和修改该代码来支持您的场景,但如果我是您,我会坚持支持旧版本的反序列化,看起来不那么困惑。

EDIT2:我无法想出任何真正直接的标准技术来消除坏处而不编辑 BadApple。我认为您可能必须使用自定义反序列化来滚动自己的集合序列化,这在反序列化时会跳过坏苹果。如果直接在 AppleHolder 中执行此操作,它会是什么样子(我会使用此功能创建一个单独的列表类型,但我认为这个示例更清晰):

public class AppleHolder implements Serializable{
static int START_OF_APPLE_MAGIC=120;
List<Apple> apples=new ArrayList<Apple>();
double otherData=15;

private void writeObject(ObjectOutputStream o)
throws IOException {
o.writeInt(apples.size());
for(Apple a: apples) {
o.write(START_OF_APPLE_MAGIC);
o.writeObject(a);
}
o.writeObject(otherData);
}

private void readObject(ObjectInputStream o)
throws IOException, ClassNotFoundException {
int appleCount = o.readInt();
apples = new ArrayList<Apple>(appleCount);
for(int i=0; i<appleCount; i++) {
try {
while(o.read() != START_OF_APPLE_MAGIC) {
//fast forward to boundary. Maybe add a max here to avoid infinite loops.
}
apples.add((Apple) o.readObject());
} catch(SomethingWentBadException e) {
//Add null or nothing or what you want. Look out for failures caused by
//the value of START_OF_APPLE_MAGIC contained in ordinary fields
apples.add(null);
}
}
otherData = (double) o.readObject();
}
}

我使用了一个列表,因为如果您不读回所有对象并且不使用空占位符(未知的确切读回大小),那么会更容易。该示例应该适用于数组,尽管只需进行一些细微的调整。

EDIT3:我用魔法边界值更新了示例。这实在是太黑客了。我使用了一个字节值,否则我们无法确定对象反序列化是否读取了均匀数量的字节(对齐问题)。

关于java - 反序列化包含一些不可反序列化对象的数组(抢救可反序列化部分),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20914158/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com