What is a serialVersionUID and why should I use it?

Viewed 1084940

Eclipse issues warnings when a serialVersionUID is missing.

The serializable class Foo does not declare a static final serialVersionUID field of type long

What is serialVersionUID and why is it important? Please show an example where missing serialVersionUID will cause a problem.

25 Answers

The docs for java.io.Serializable are probably about as good an explanation as you'll get:

The serialization runtime associates with each serializable class a version number, called a serialVersionUID, which is used during deserialization to verify that the sender and receiver of a serialized object have loaded classes for that object that are compatible with respect to serialization. If the receiver has loaded a class for the object that has a different serialVersionUID than that of the corresponding sender's class, then deserialization will result in an InvalidClassException. A serializable class can declare its own serialVersionUID explicitly by declaring a field named serialVersionUID that must be static, final, and of type long:

ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;

If a serializable class does not explicitly declare a serialVersionUID, then the serialization runtime will calculate a default serialVersionUID value for that class based on various aspects of the class, as described in the Java(TM) Object Serialization Specification. However, it is strongly recommended that all serializable classes explicitly declare serialVersionUID values, since the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementations, and can thus result in unexpected InvalidClassExceptions during deserialization. Therefore, to guarantee a consistent serialVersionUID value across different java compiler implementations, a serializable class must declare an explicit serialVersionUID value. It is also strongly advised that explicit serialVersionUID declarations use the private modifier where possible, since such declarations apply only to the immediately declaring class — serialVersionUID fields are not useful as inherited members.

If you're serializing just because you have to serialize for the implementation's sake (who cares if you serialize for an HTTPSession, for instance...if it's stored or not, you probably don't care about de-serializing a form object), then you can ignore this.

If you're actually using serialization, it only matters if you plan on storing and retrieving objects using serialization directly. The serialVersionUID represents your class version, and you should increment it if the current version of your class is not backwards compatible with its previous version.

Most of the time, you will probably not use serialization directly. If this is the case, generate a default SerialVersionUID by clicking the quick fix option and don't worry about it.

I can't pass up this opportunity to plug Josh Bloch's book Effective Java (2nd Edition). Chapter 10 is an indispensible resource on Java serialization.

Per Josh, the automatically-generated UID is generated based on a class name, implemented interfaces, and all public and protected members. Changing any of these in any way will change the serialVersionUID. So you don't need to mess with them only if you are certain that no more than one version of the class will ever be serialized (either across processes or retrieved from storage at a later time).

If you ignore them for now, and find later that you need to change the class in some way but maintain compatibility w/ old version of the class, you can use the JDK tool serialver to generate the serialVersionUID on the old class, and explicitly set that on the new class. (Depending on your changes you may need to also implement custom serialization by adding writeObject and readObject methods - see Serializable javadoc or aforementioned chapter 10.)

You can tell Eclipse to ignore these serialVersionUID warnings:

Window > Preferences > Java > Compiler > Errors / Warnings > Potential Programming Problems

In case you didn't know, there are a lot of other warnings you can enable in this section (or even have some reported as errors), many are very useful:

  • Potential Programming Problems: Possible accidental boolean assignment
  • Potential Programming Problems: Null pointer access
  • Unnecessary code: Local variable is never read
  • Unnecessary code: Redundant null check
  • Unnecessary code: Unnecessary cast or 'instanceof'

and many more.

First I need to explain what serialization is.

Serialization allows to convert an object to a stream, for sending that object over the network OR Save to file OR save into DB for letter usage.

There are some rules for serialization.

  • An object is serializable only if its class or its superclass implements the Serializable interface

  • An object is serializable (itself implements the Serializable interface) even if its superclass is not. However, the first superclass in the hierarchy of the serializable class, that does not implements Serializable interface, MUST have a no-arg constructor. If this is violated, readObject() will produce a java.io.InvalidClassException in runtime

  • All primitive types are serializable.

  • Transient fields (with transient modifier) are NOT serialized, (i.e., not saved or restored). A class that implements Serializable must mark transient fields of classes that do not support serialization (e.g., a file stream).

  • Static fields (with static modifier) are not serialized.

When Object is serialized, Java Runtime associates the serial version number aka, the serialVersionID.

Where we need serialVersionID:

During the deserialization to verify that sender and receiver are compatible with respect to serialization. If the receiver loaded the class with a different serialVersionID then deserialization will end with InvalidClassCastException.
A serializable class can declare its own serialVersionUID explicitly by declaring a field named serialVersionUID that must be static, final, and of type long.

Let's try this with an example.

import java.io.Serializable;

public class Employee implements Serializable {
    private static final long serialVersionUID = 1L;
    private String empname;
    private byte empage;

    public String getEmpName() {
        return name;
    }

    public void setEmpName(String empname) {
        this.empname = empname;
    }

    public byte getEmpAge() {
        return empage;
    }

    public void setEmpAge(byte empage) {
        this.empage = empage;
    }

    public String whoIsThis() {
        return getEmpName() + " is " + getEmpAge() + "years old";
    }
}

Create Serialize Object

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class Writer {
    public static void main(String[] args) throws IOException {
        Employee employee = new Employee();
        employee.setEmpName("Jagdish");
        employee.setEmpAge((byte) 30);

        FileOutputStream fout = new
                FileOutputStream("/users/Jagdish.vala/employee.obj");
        ObjectOutputStream oos = new ObjectOutputStream(fout);
        oos.writeObject(employee);
        oos.close();
        System.out.println("Process complete");
    }
}

Deserialize the object

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

public class Reader {
    public static void main(String[] args) throws ClassNotFoundException, IOException {
        Employee employee = new Employee();
        FileInputStream fin = new FileInputStream("/users/Jagdish.vala/employee.obj");
        ObjectInputStream ois = new ObjectInputStream(fin);
        employee = (Employee) ois.readObject();
        ois.close();
        System.out.println(employee.whoIsThis());
    }
}

NOTE: Now change the serialVersionUID of the Employee class and save:

private static final long serialVersionUID = 4L;

And execute the Reader class. Not to execute the Writer class and you will get the exception.

Exception in thread "main" java.io.InvalidClassException: 
com.jagdish.vala.java.serialVersion.Employee; local class incompatible: 
stream classdesc serialVersionUID = 1, local class serialVersionUID = 4
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:616)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1623)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1518)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1774)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)
at com.krishantha.sample.java.serialVersion.Reader.main(Reader.java:14)

If you will never need to serialize your objects to byte array and send/store them, then you don't need to worry about it. If you do, then you must consider your serialVersionUID since the deserializer of the object will match it to the version of object its classloader has. Read more about it in the Java Language Specification.

If you get this warning on a class you don't ever think about serializing, and that you didn't declare yourself implements Serializable, it is often because you inherited from a superclass, which implements Serializable. Often then it would be better to delegate to such a object instead of using inheritance.

So, instead of

public class MyExample extends ArrayList<String> {

    public MyExample() {
        super();
    }
    ...
}

do

public class MyExample {
    private List<String> myList;

    public MyExample() {
         this.myList = new ArrayList<String>();
    }
    ...
}

and in the relevant methods call myList.foo() instead of this.foo() (or super.foo()). (This does not fit in all cases, but still quite often.)

I often see people extending JFrame or such, when they really only need to delegate to this. (This also helps for auto-completing in a IDE, since JFrame has hundreds of methods, which you don't need when you want to call your custom ones on your class.)

One case where the warning (or the serialVersionUID) is unavoidable is when you extend from AbstractAction, normally in a anonymous class, only adding the actionPerformed-method. I think there shouldn't be a warning in this case (since you normally can't reliable serialize and deserialize such anonymous classes anyway accross different versions of your class), but I'm not sure how the compiler could recognize this.

It would be nice if CheckStyle could verify that the serialVersionUID on a class that implements Serializable has a good value, i.e. that it matches what the serial version id generator would produce. If you have a project with lots of serializable DTOs, for example, remembering to delete the existing serialVersionUID and regenerate it is a pain, and currently the only way (that I know of) to verify this is to regenerate for each class and compare to the old one. This is very very painful.

A Simple Explanation:

  1. Are you serializing data?

    Serialization is basically writing class data to a file/stream/etc. De-serialization is reading that data back to a class.

  2. Do you intend to go into production?

    If you are just testing something with unimportant/fake data, then don't worry about it (unless you are testing serialization directly).

  3. Is this the first version?

    If so, set serialVersionUID=1L.

  4. Is this the second, third, etc. prod version?

    Now you need to worry about serialVersionUID, and should look into it in depth.

Basically, if you don't update the version correctly when you update a class you need to write/read, you will get an error when you try to read old data.

To tell the long story short this field is used to check if serialized data can be deserialized correctly. Serialization and deserialization are often made by different copies of program - for example server converts object to string and client converts received string to object. This field tells that both operates with same idea about what this object is. This field helps when:

  • you have many different copies of your program in different places (like 1 server and 100 clients). If you will change your object, alter your version number and forget to update one this clients, it will know that he is not capable of deserialization

  • you have stored your data in some file and later on you try to open it with updated version of your program with modified object - you will know that this file is not compatible if you keep your version right

When is it important?

Most obvious - if you add some fields to your object, older versions will not be able to use them because they do not have these fields in their object structure.

Less obvious - When you deserialize object, fields that where not present in string will be kept as NULL. If you have removed field from your object, older versions will keep this field as allways-NULL that can lead to misbehavior if older versions rely on data in this field (anyway you have created it for something, not just for fun :-) )

Least obvious - Sometimes you change the idea you put in some field's meaning. For example when you are 12 years old you mean "bicycle" under "bike", but when you are 18 you mean "motorcycle" - if your friends will invite you to "bike ride across city" and you will be the only one who came on bicycle, you will undestand how important it is to keep same meaning across fields :-)

'serialVersionUID' is a 64 bit number used to uniquely identify a class during deserialization process. When you serialize an object, serialVersionUID of the class also written to the file. Whenever you deserialize this object, java run time extract this serialVersionUID value from the serialized data and compare the same value associate with the class. If both do not match, then 'java.io.InvalidClassException' will be thrown.

If a serializable class do not explicitly declare a serialVersionUID, then serialization runtime will calculate serialVersionUID value for that class based on various aspects of the class like fields, methods etc.,, You can refer this link for demo application.

Firstly to answer your question, when we don't declare SerialVersionUID in our class, Java runtime generates it for us, but that process is sensitive to many class meta data including number of fields, type of fields, access modifier of fields, interface implemented by class etc. Therefore it is recommended to declare it ourselves and Eclipse is warning you about the same.

Serialization: We often work with important objects whose state (data in the variables of the object) is so important that we can not risk to lose it due to power/system failures (or) network failures in case of sending the object state to other machine. The solution for this problem is named "Persistence" which simply means persisting (holding/saving) the data. Serialization is one of many other ways to achieve persistence (by saving data to disk/memory). When saving the state of the object, it is important to create an identity for the object, to be able to properly read it back (de-serialization). This unique identification is ID is SerialVersionUID.

Related