extracting the only serialversionuid from a stream

Hello all,

I know some naughty little programmers who serialized an object (really multiple objects) and stored it to a database in a production system. Unfortunately, they did not define serialVersionUID's for their classes and thus we are getting exceptions saying the UID's don't match. I assure you all that the classes are still indeed compatible in terms of any changes made.

In trying to solve this problem, I think the "easiest" way is to figure out what the stored serialVersionUID field is, and then paste that into our source code. One way to do this would be to enter in a random uid and check the exception text, which will tell the stored vs. the calculated uid. That however is tedious.

An only slightly better idea I came up with was to do something like this pseudo code:

foreach (array of bytes arr : from database){

//MyObjectInputStream extends ObjectInputStream, simply

//making public the readClassDescriptor() function

MyObjectInputStream stream =new

MyObjectInputStream(new ByteArrayInputStream(arr));

//this function simply runs through the array looking for this constant

int pos = find(arr, ObjectStreamConstants.TS_CLASDESC);

stream.skip(pos + 1);

stream.readClassDescriptor();

long suid = stream.getSuid()//or whatever the actual function is

return suid;

}

When I implemented this, I got an EOFException when calling readClassDescriptor.

I'm not exactly sure where the bug is, but my first question to you all is, is there anything obviously wrong with this approach?

Secondly, is there a better way (other than beating the developers who forgot to define their UID's) to go about this that I am completely missing?

Thanks in advance!!

Justin

[2156 byte] By [justinmiller621a] at [2007-10-3 3:13:39]
# 1
Put the class back the way it was temporarily and run serialver
ejpa at 2007-7-14 21:04:41 > top of Java-index,Core,Core APIs...
# 2

Well, part of the problem is, we don't know exactly what changed. In fact, we don't think anything changed. If I'm not mistaken, the JVM spec doesn't guarantee that it will calculate the same UID every time. Theoretically it should, but there are no guarantees, which is I think what we're running into.

justinmiller621a at 2007-7-14 21:04:41 > top of Java-index,Core,Core APIs...
# 3
Well then just run serialver and try it. Also the exception should print out the expected serialverUID if I remember correctly.
ejpa at 2007-7-14 21:04:41 > top of Java-index,Core,Core APIs...
# 4

First of all, I want to thank you for your input. I appreciate the time you've taken to read and respond to my post.

The algorithm that the jvm uses the calculate UID's and the algorithm serialver uses is one and the same. Simply running serialver would produce the different, incorrect uid.

And yes, the exception does tell you what the expected uid is. However, there are quite a number of Serializable objects we are storing. Where reading the expected uid from the exception message would work, it would be extremely tedious. If worse came to worse I would go that route and I don't intend on wasting too much time coming up with a better solution. But if one does exist that I haven't thought of, and/or someone has a thought as to why my proposed solution isn't working, then I'd like to explore that first.

Again, thanks for the help.

justinmiller621a at 2007-7-14 21:04:41 > top of Java-index,Core,Core APIs...
# 5

Yes. You need to run serialverUID against the old version or with the old JDK or whatever is producing the difference.

And shoot the programmers who did this.

Getting back to your code in the OP, it looks OK to me apart from the probable non-uniqueness of TC_CLASSDESC. You need to parse the stream more elaborately than you are.

ejpa at 2007-7-14 21:04:41 > top of Java-index,Core,Core APIs...
# 6
The problem with the code in your OP is that ObjectInputStream reads in blocks and can't be persuaded not to, so you can't just position or rewind to a particular spot and expect the lower level reads to work. It knows what it's already read.
ejpa at 2007-7-14 21:04:41 > top of Java-index,Core,Core APIs...
# 7
Ahhhh, indeed. Ok... I replaced the ObjectInputSream with a DataInputStream. Then instead of calling readClassDescriptor, I do a readUTF() to get the class name and then a readLong() to get the suid and that works great!Thanks for all your help!
justinmiller621a at 2007-7-14 21:04:41 > top of Java-index,Core,Core APIs...
# 8
If I remeber right when the serialVersion mismatch the message of the exception shows the serialVersionUID s of both serialized data and the class in your runtime.
LRMKa at 2007-7-14 21:04:41 > top of Java-index,Core,Core APIs...