当我尝试反序列化java.math.BigDecimal时,我收到以下错误:
java.io.InvalidClassException: java.math.BigDecimal; local class incompatible:
stream classdesc serialVersionUID = 6108874887139371087,
local class serialVersionUID = 6108874887143696463
我知道如果你在没有定义serialVersionUID
的情况下实现Serializable接口会发生这个错误,但是我的类确实定义了它:
public class Foo implements java.io.Serializable {
private static final long serialVersionUID = -2280646288949622888L;
private int a;
private long b;
private java.lang.String c;
private java.math.BigDecimal d;
}
此外,它特别抱怨作为JDK一部分的BigDecimal,如果我信任Eclipse的反编译器,还会定义serialVersionUID
:
private static final long serialVersionUID = 6108874887143696463L;
我已经读过in some cases (such as using GWT),你可以使用不同的串行版本来实现BigDecimal类的不同实现,这将避免正确的反序列化。它也可能发生在不同机器上具有相同类的不同版本。但就我而言,我在同一台机器上进行序列化和反序列化,在同一个JBoss实例中...
查看this similar question,我猜我的序列化过程肯定存在问题,但我无法弄明白。这是我使用的代码:
static InputStream serialize(Foo[] array) throws IOException {
ByteArrayOutputStream baos = null;
ObjectOutputStream oos = null;
try {
baos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(baos);
oos.writeObject(array);
return new ByteArrayInputStream(baos.toByteArray());
} finally {
close(oos);
close(baos);
}
}
static Foo[] deserialize(InputStream is) throws IOException, ClassNotFoundException {
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(is);
return (Foo[]) ois.readObject();
} finally {
close(ois);
}
}
编辑:我忘了提到数据在序列化后存储到磁盘,并在反序列化之前从那里读取。也许这就是它被破坏的地方。要阅读我只需使用new FileInputStream(file)
。要写,我用这个:
static void write(File file, InputStream is) throws IOException {
FileWriter fw = null;
InputStreamReader isr = null;
try {
fw = new FileWriter(file, true);
isr = new InputStreamReader(is);
char[] buffer = new char[8096];
int bytesRead;
while ((bytesRead = isr.read(buffer)) != -1) {
fw.write(buffer, 0, bytesRead);
}
} finally {
close(fw);
close(isr);
}
}
可能是因为我使用char[]
作为缓冲区,但输入流是从byte[]
生成的?那应该不是问题,对吗?
答案 0 :(得分:2)
在某些地方,序列化数据被错误处理和损坏。
查看两个serialVersionUID值,很明显只有一个字节不同,这表明它不仅仅是类不匹配的情况。
您的信息流更有可能被破坏。请注意,serialVersionUID通常也会“意外地”充当一种损坏检查,因为它是一个必须完全匹配的幻数。
十六进制的真正serialVersionUID是54C71557F981284F
。您在流中拥有的是54C71557F93F284F
。请注意,81
已更改为3F
。 3F
是?
的ASCII代码,它是解码Java错误的默认替换字符。
这有力地表明,在某些时候,您的数据被错误地视为文本数据。由于正确数据中的值为81
,因此用于错误“解码”数据的编码很可能是ISO-8859-1,而且没有任何内容分配给该代码点。
tl; dr 在序列化数据转换为String
并返回byte[]
的某个地方,这是一个糟糕的主意,必须避免。将二进制数据视为二进制数据(使用byte[]
和InputStream
/ Outputstream
)。避免处理文本数据的任何内容(即不要使用String
,避免使用Reader
/ Writer
)。