I am saving a field in my app as a HashSet<String>, defined as such:
@DatabaseField(dataType = DataType.SERIALIZABLE)
private HashSet<String> allUsers;
Some devices are occasionally having an error where this field is serialized with the incorrect size byte, and thus it cannot be deserialized. Example error message with dummy data:
java.sql.SQLException: Could not read serialized object from byte array: [-84,
-19, 0, 5, 115, 114, 0, 17, 106, 97, 118, 97, 46, 117, 116, 105, 108, 46, 72,
97, 115, 104, 83, 101, 116, -70, 68, -123, -107, -106, -72, -73, 52, 3, 0, 0,
120, 112, 119, 12, 0, 0, 0, 16, 63, 64, 0, 0, 0, 0, 0, /* this is the problem
byte */ 3, 116, 0, 4, 115, 111, 109, 101, 116, 0, 4, 100, 97, 116, 97, 120]
If I correct the size byte to create a new array like so:
[-84, -19, 0, 5, 115, 114, 0, 17, 106, 97, 118, 97, 46, 117, 116, 105, 108, 46,
72, 97, 115, 104, 83, 101, 116, -70, 68, -123, -107, -106, -72, -73, 52, 3, 0,
0, 120, 112, 119, 12, 0, 0, 0, 16, 63, 64, 0, 0, 0, 0, 0, /* correct size is
2 */ 2, 116, 0, 4, 115, 111, 109, 101, 116, 0, 4, 100, 97, 116, 97, 120]
I can then deserialize the array to find a HashSet containing two strings.
I want to know possible reasons for a HashSet being serialized with the wrong size byte in this way. I have not been able to determine steps to reproduce this issue but it has happened on several devices. However, the vast majority of devices this app runs on do not have this issue.
I have tried reproducing the issue by serializing a HashSet, then deserializing it, adding and removing objects, and serializing again. But I was not able to reproduce the issue. I want to know if there is a known reason for HashSets in Java to be serialized incorrectly like this.
Some devices are occasionally having an error where this field is serialized with the incorrect size byte, and thus it cannot be deserialized.
My best guess is that something is modifying the HashSet
in another thread. All ORMLite is doing is serializing the data into a buffer and then storing it as a bag o' bytes. Check out the rather simple code from SerializableType.sqlArgToJava(...). It's basically doing:
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
objOutStream = new ObjectOutputStream(outStream);
objOutStream.writeObject(obj);
objOutStream.close();
return outStream.toByteArray();
As you mention, the serialized HashSet
says that its size is 3 however there are only 2 strings stored in the set. I can see that happening when an element gets added to the HashSet
and the size field has been updated in the persisting thread's memory but not the underlying node array because of memory synchronization issues between threads. It's also suspicious that the serialized stream had that problem was wasn't in the middle of a string or some other data.