Java Serializable and serialVersionUID

January 14th, 2010 by nils

Here’s a question:

Is a serialVerionUID required on abstract classes?

My first thought: No way! If the serialVersionUID is used by the serialization mechanism to check whether some serialized data is compatible with a serializable class, abstract classes (that will never be instantiated, and thus, never be serialized directly) don’t need one! The problem is that the entire inheritance tree is checked when a class is de-serialized — and that includes abstract base classes. A simple example illustrates the problem:

If we have an abstract base class …

import java.io.Serializable;

public abstract class Base
implements Serializable {}

… and a sub-class that declares a serialVersionUID …

public class Sub extends Base {
    private static final long serialVersionUID =
      -7913545780181427623L;
}

… and we create an instance of the sub-class and serialize it to a file …

...
Sub sub1 = new Sub();
try {
    FileOutputStream fout = new FileOutputStream("sub.dat");
    ObjectOutputStream oos = new ObjectOutputStream(fout);
    oos.writeObject(sub1);
    oos.close();
} catch (Exception e) {
    e.printStackTrace();
}

… and then we change the base class by e.g. adding an int field …

import java.io.Serializable;

public abstract class Base
implements Serializable {
    int a = 0;
}

… and try to de-serialize the sub-class …

Sub sub2 = null;
// Load the file and de-serialize the object
try {
    FileInputStream fin = new FileInputStream("sub.dat");
    ObjectInputStream ois = new ObjectInputStream(fin);
    sub2 = (Sub) ois.readObject();
    ois.close();
} catch (Exception e) {
    e.printStackTrace();
}

… we’ll get a “java.io.InvalidClassException”.

If we do the same thing, but define a serialVersionUID in the abstract base class, the exception would not occur. The reason for this is, that if a serialVersionUID is not explicitly declared, the JVM will calculate a default one, “based on various aspects of the class” [1]. This is a great mechanism, at first glance it even seems to be better than creating the id manually — if the class changes, these changes are automatically reflected in the generated id. But, this mechanism can differ based on the VM If you would run this example on one VM and then try to de-serialize the same “sub.dat” file with a different VM, without modifying the base class, it is possible that you would get an “InvalidClassException”, simply because the VM uses a different mechanism to calculate the default serialVersionUID. This is why it is recommended to manually declare the serialVersionUID.

However, this also means that, if we change a serializable class and thereby make it incompatible with previously serialized instances, we have to update the serialVersionUID!

Now if we think about software maintenance and data integrity, there should be a way to migrate existing serialized data to new versions of the serializable class. I’d be interested to know if there is an official recommendation for this, but didn’t investigate further yet.

It would also be interesting to see how OR-mapping frameworks fit into the picture. There is an interesting thread on using Serializable and what to do with the serialVersionUID in the hibernate JIRA: http://opensource.atlassian.com/projects/hibernate/browse/HBX-964

I’d be interested to know what others think about this, so please feel free to comment!

[1] http://java.sun.com/javase/6/docs/api/java/io/Serializable.html

1 Comment

  1. First of all thanks for writing such a clear post on this topic.

    Without diving too deep in the subject I would like to add that one could also use the
    Externalizable interface instead of Serializable. This interface extends
    the java.io.Serializable interface and adds two methods :

    public void writeExternal(ObjectOutput out)
    public void readExternal(ObjectInput in)

    These methods are automatically called during serialization and de-serialization.
    Therefore, by providing code for these methods, you can implement your own serialization-specific
    operations, and, thus, have control over what data to, or not to serialize.

    As a result using the Externalizable interface will provide you fine grained control
    over the object which you would like to migrate to a newer version of a class.

    Comment by Arnold Reuser — February 18, 2010 @ 4:53 pm

RSS feed for comments on this post.

Sorry, the comment form is closed at this time.