反序列化 BigDecimal 时出错
Error deserializing a BigDecimal
当我尝试反序列化 java.math.BigDecimal 时出现以下错误:
java.io.InvalidClassException: java.math.BigDecimal; local class incompatible:
stream classdesc serialVersionUID = 6108874887139371087,
local class serialVersionUID = 6108874887143696463
我知道如果您在未定义 serialVersionUID
的情况下实现 Serializable 接口,可能会发生此错误,但我的 class 确实定义了它:
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;
}
此外,它特别抱怨 BigDecimal,它是 JDK 的一部分,并且还定义了 serialVersionUID
如果我信任 Eclipse 的反编译器:
private static final long serialVersionUID = 6108874887143696463L;
我读过 in some cases (such as using GWT),您可以使用不同的 BigDecimal class 实现,使用不同的串行版本,这将避免正确的反序列化。它也可能发生在不同机器上具有相同 class 的不同版本。但就我而言,我在同一台机器上的同一个 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[]
生成的?这应该不是问题,对吧?
您的序列化数据在某个过程中被错误处理和破坏。
查看两个 serialVersionUID 值,很明显只有一个字节不同,这表明这不仅仅是 类.
不匹配的情况
您的流很可能已损坏。请注意,serialVersionUID 通常还 "accidentally" 作为一种损坏检查,因为它是一个必须完全匹配的神奇数字。
真正的十六进制serialVersionUID是54C71557F981284F
。您的信息流中的那个是 54C71557F93F284F
。请注意,81
已更改为 3F
。 3F
是 ?
的 ASCII 码,它是 Java.
中解码错误的默认替换字符
这强烈表明您的数据在某些时候被错误地视为文本数据。由于正确数据中的值是 81
,很有可能用于错误 "decode" 您的数据的编码是 ISO-8859-1,它没有为该代码点分配任何内容。
tl;dr 在您的序列化数据被转换为 String
并返回到 byte[]
的过程中,这是一个糟糕的想法,必须这样做避免。将二进制数据视为二进制数据(使用 byte[]
和 InputStream
/Outputstream
)。避免任何处理文本数据的东西(即不要使用 String
,避免使用 Reader
/Writer
)。
当我尝试反序列化 java.math.BigDecimal 时出现以下错误:
java.io.InvalidClassException: java.math.BigDecimal; local class incompatible:
stream classdesc serialVersionUID = 6108874887139371087,
local class serialVersionUID = 6108874887143696463
我知道如果您在未定义 serialVersionUID
的情况下实现 Serializable 接口,可能会发生此错误,但我的 class 确实定义了它:
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;
}
此外,它特别抱怨 BigDecimal,它是 JDK 的一部分,并且还定义了 serialVersionUID
如果我信任 Eclipse 的反编译器:
private static final long serialVersionUID = 6108874887143696463L;
我读过 in some cases (such as using GWT),您可以使用不同的 BigDecimal class 实现,使用不同的串行版本,这将避免正确的反序列化。它也可能发生在不同机器上具有相同 class 的不同版本。但就我而言,我在同一台机器上的同一个 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[]
生成的?这应该不是问题,对吧?
您的序列化数据在某个过程中被错误处理和破坏。
查看两个 serialVersionUID 值,很明显只有一个字节不同,这表明这不仅仅是 类.
不匹配的情况您的流很可能已损坏。请注意,serialVersionUID 通常还 "accidentally" 作为一种损坏检查,因为它是一个必须完全匹配的神奇数字。
真正的十六进制serialVersionUID是54C71557F981284F
。您的信息流中的那个是 54C71557F93F284F
。请注意,81
已更改为 3F
。 3F
是 ?
的 ASCII 码,它是 Java.
这强烈表明您的数据在某些时候被错误地视为文本数据。由于正确数据中的值是 81
,很有可能用于错误 "decode" 您的数据的编码是 ISO-8859-1,它没有为该代码点分配任何内容。
tl;dr 在您的序列化数据被转换为 String
并返回到 byte[]
的过程中,这是一个糟糕的想法,必须这样做避免。将二进制数据视为二进制数据(使用 byte[]
和 InputStream
/Outputstream
)。避免任何处理文本数据的东西(即不要使用 String
,避免使用 Reader
/Writer
)。