views:

1797

answers:

4

A few months back I serialized a java.io.Serializable object into a file. Now I need to read the contents, but since then the serialVersionUID has changed, and now I'm getting a "class incompatible" error. I know for a fact that none of the data members have changed, so the only barrier is the serialVersionUID check.

Is there a way to either disable the check or to modify the serialVersionUID in the binary file?

CLARIFICATION

This question is assuming that I can't edit the source. Is there a way I can hack the .class file or perhaps hack the serialized object file (use a hex editor and change a value at some certain offset)?

A: 

It is documented that Serialization is not intended to be used for persisting data. In order to get that data back, you will need to downgrade your version of the JVM to the version that was used to output that data.

For future reference, don't use serialization to persist data between sessions of the JVM.

Matthew Brubaker
You *can* use serialization in this manner as long as you set the serialVersionUID. From the Serializable doc - "Therefore, to guarantee a consistent serialVersionUID value across different java compiler implementations, a serializable class must declare an explicit serialVersionUID value."
CurtainDog
+2  A: 

Why not modify the serialVersionUID in your current version instead as described in the Serialization documentation?

Jon Skeet
The way his question was written indicates that the object is not under his control to be able to make that change.
Matthew Brubaker
But if that is the case, then yes. Changing the serialVersionUID back to what it was when he wrote the data out would allow him to read it back in.
Matthew Brubaker
It doesn't matter if the class isn't under his control. He can just write a new one with the same name, members, and serialVersionUID
Adrian Pronk
This will work only if the class has no elements that will break on deserialization from the old vers. If you remove a member variable and try to fool it with serialVersionUID it will throw an Exception deserializing from the old files.
Steve B.
@SteveB: Read the question: " I know for a fact that none of the data members have changed, so the only barrier is the serialVersionUID check."
Jon Skeet
+1  A: 

As a hack, you can generate the serialVer your jvm is probably using using the serialver tool:

serialver -classpath whatever com.foo.bar.MyClass

If you then manually set the serialVerUID in your class it ought to match and you ought to be able to load, assuming you haven't changed the class in such a way as to invalidate.

Steve B.
For this to work, you need access to the class file as it was when the object it was serialized. Hopefully it's in the Version Control archive?
Adrian Pronk
You could also write your own readObject, I think that you'd probably be able to read the fields in declared order.
Steve B.
A: 

I recently found myself in a similar situation--I had some serialized objects that I had to read, the serialVersionUID of those objects was different than the newest version and, in my case, there were a couple of different serialVersionUIDs stored in the file for the same class (stored at different times, obviously). So I didn't have the luxury of modifying the class and setting its serialVersionUID; I actually had to go in and modify the stored data.

What I figured out (by reading the java.io source code) is that an object gets serialized by first storing the class name (using writeUTF()) and then immediately after using writeLong() to save the serialVersionUID.

My solution was to catch the exception then go back, look for the class name, and immediately after the class name replace the old serialVersionUID with the new.