Java serialization - java.io.InvalidClassException local class incompatible

JavaSerializationDeserialization

Java Problem Overview


I've got a public class, which implements Serializable, that is extended by multiple other classes. Only those subclasses were ever serialized before - never the super class.

The super class had defined a serialVersionUID.

I'm not sure if it matters, but it was not marked private, but rather it just had the default protection - you might say it was package protected

static final long serialVersionUID = -7588980448693010399L;

The super class, nor any of the subclasses, however implemented readObject or writeObject, and none of the subclasses had an explicitly defined serialVersionUID. I figured one defined in the superclass would be sufficient.

Despite all this, things were fine as far as reading back previously serialized objects until a new instance variable, a List/ArrayList, along with a new method was added to the super class, and some private instance variables were added to one of its subclasses.

Now when trying to read back previously serialized objects, an exception is being thrown. One similar to this:

com.SomeCompany.SomeSubClass; local class incompatible: stream classdesc serialVersionUID = 1597316331807173261, local class serialVersionUID = -3344057582987646196

I'm assuming this is caused because the default serialVersionUID, which was used because I didn't declare one in any of the subclasses, has now changed due to the changes in the superclass and one subclass.

Suggestions on how to get out of this dilemma would be appreciated. I'm assuming I need to implement readObject and writeObject, but other than invoking defaultReadObject() and defaultWriteObject(), I'm not exactly sure what I need to do. Nor do I know if I need to add serialVerisonUIDs to all of the subclasses or if readObject and writeObject need to be implemented by each subclass, or if I can just implement them once, assuming I need to at all, in the superclass.

Java Solutions


Solution 1 - Java

@DanielChapman gives a good explanation of serialVersionUID, but no solution. the solution is this: run the serialver program on all your old classes. put these serialVersionUID values in your current versions of the classes. as long as the current classes are serial compatible with the old versions, you should be fine. (note for future code: you should always have a serialVersionUID on all Serializable classes)

if the new versions are not serial compatible, then you need to do some magic with a custom readObject implementation (you would only need a custom writeObject if you were trying to write new class data which would be compatible with old code). generally speaking adding or removing class fields does not make a class serial incompatible. changing the type of existing fields usually will.

Of course, even if the new class is serial compatible, you may still want a custom readObject implementation. you may want this if you want to fill in any new fields which are missing from data saved from old versions of the class (e.g. you have a new List field which you want to initialize to an empty list when loading old class data).

Solution 2 - Java

The short answer here is the serial ID is computed via a hash if you don't specify it. (Static members are not inherited--they are static, there's only (1) and it belongs to the class).

http://docs.oracle.com/javase/6/docs/platform/serialization/spec/class.html

> The getSerialVersionUID method returns the serialVersionUID of this > class. Refer to Section 4.6, "Stream Unique Identifiers." If not > specified by the class, the value returned is a hash computed from the > class's name, interfaces, methods, and fields using the Secure Hash > Algorithm (SHA) as defined by the National Institute of Standards.

If you alter a class or its hierarchy your hash will be different. This is a good thing. Your objects are different now that they have different members. As such, if you read it back in from its serialized form it is in fact a different object--thus the exception.

The long answer is the serialization is extremely useful, but probably shouldn't be used for persistence unless there's no other way to do it. Its a dangerous path specifically because of what you're experiencing. You should consider a database, XML, a file format and probably a JPA or other persistence structure for a pure Java project.

Solution 3 - Java

For me, I forgot to add the default serial id.

private static final long serialVersionUID = 1L;

Solution 4 - Java

This worked for me:

If you wrote your Serialized class object into a file, then made some changes to file and compiled it, and then you try to read an object, then this will happen.

So, write the necessary objects to file again if a class is modified and recompiled.

PS: This is NOT a solution; was meant to be a workaround.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDaleView Question on Stackoverflow
Solution 1 - JavajtahlbornView Answer on Stackoverflow
Solution 2 - JavaDaniel B. ChapmanView Answer on Stackoverflow
Solution 3 - JavataxeetaView Answer on Stackoverflow
Solution 4 - JavaskrtbhtngrView Answer on Stackoverflow