I'm getting the following error when I try to deserialize a java.math.BigDecimal:
java.io.InvalidClassException: java.math.BigDecimal; local class incompatible:
stream classdesc serialVersionUID = 6108874887139371087,
local class serialVersionUID = 6108874887143696463
I know that this error can happen if you implement the Serializable interface without defining serialVersionUID
, but my class does define it:
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;
}
Besides, it's complaining specifically about the BigDecimal, which is part of the JDK, and also defines the serialVersionUID
if I trust Eclipse's decompiler:
private static final long serialVersionUID = 6108874887143696463L;
I have read that in some cases (such as using GWT), you can have different implementations of the BigDecimal class, with different serial versions, which would avoid proper deserialization. It also can happen having different versions of the same class across different machines. But in my case, I'm doing the serialization and deserialization in the same machine, in the same JBoss instance...
Looking at this similar question, I guess there must be a problem with my serialization process, but I can't figure it out. This is the code I'm using:
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);
}
}
Edit: I forgot to mention that the data is being stored to disk after serialization, and read from there before deserializing. So maybe that's where it's getting corrupted. To read I just use new FileInputStream(file)
. To write, I use this:
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);
}
}
Could it be because I'm using a char[]
as buffer, but the input stream was generated from a byte[]
? That shouldn't be an issue, right?
Somewhere along the way your serialized data was incorrectly handled and mangled.
Looking at the two serialVersionUID values it becomes clear that only a single byte is different, which suggests that it's not just a case of mismatching classes.
It's much more likely that your stream got corrupted. Note that the serialVersionUID often also "accidentally" acts as a kind of corruption check, since it's a magic number that has to match exactly.
The real serialVersionUID in hex is 54C71557F981284F
. The one you have in your stream is 54C71557F93F284F
. Note that 81
changed to 3F
. 3F
is the ASCII code for ?
which is the default replacement character for decoding errors in Java.
This strongly suggests that at some point your data was incorrectly treated as text data. Since the value in the correct data is 81
, there's a good chance that the encoding used to wrongly "decode" your data was ISO-8859-1, which doesn't have anything assigned to that code point.
tl;dr somewhere along the way your serialized data was converted to a String
and back to a byte[]
and that's a terrible idea and must be avoided. Treat binary data as binary data (use byte[]
and InputStream
/Outputstream
). Avoid anything that handles text data (i.e. don't use String
, avoid Reader
/Writer
).