What is serialVersionUID?

If a class implements Serializable interface, your IDE worn you to add serialVersionUID or it add automatically. This variable holds a private static final long and IDE automatically declared it to 1L.
class SerializeMe implements Serializable {
private static final long serialVersionUID = 1L;
private String data;

public SerializeMe (String data) {
this.data = data;
}

public String getData() {
return data;
}
}

Field data represents some information stored in the class. Note that serialVersionUID is a static value, then it should not have been serialized. But why is this so impotent?
public class SerialVersionUIDTester {
public static void main(String [] args) throws Exception {
File file = new File("out.ser");
FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);

SerializeMe serializeMe = new SerializeMe("serialVersionUID is 1L");
oos.writeObject(serializeMe);
oos.close();

FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);

SerializeMe dto = (SerializeMe) ois.readObject();
System.out.println("data : " + dto.getData());
ois.close();
}
}

This code will serialize an instance of class SerializeMe to a file and then deserialize it back. Then the uotput is

data : serialVersionUID is 1L

It means that our object was properly serialized and deserialized. Note that the file "out.ser" was created on disk and it is still there even after the program finished. Let's see if we can read that file once again, this time without creating it first. To do that, comment out SerialVersionUIDTester's lines as follows:
public class SerialVersionUIDTester {
public static void main(String [] args) throws Exception {
File file = new File("out.ser");
//FileOutputStream fos = new FileOutputStream(file);
//ObjectOutputStream oos = new ObjectOutputStream(fos);

//SerializeMe serializeMe = new SerializeMe("serialVersionUID is 1L");
//oos.writeObject(serializeMe);
//oos.close();

FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);

SerializeMe dto = (SerializeMe) ois.readObject();
System.out.println("data : " + dto.getData());
ois.close();
}
}

This way, the main method reads the file from the disk and deserialize data stored in it. Also it gives same output as previous.

data : serialVersionUID is 1L

Now, let's see what happens, when we change the serialVersionUID value and try to deserialize once again our file. set serialVersionUID to 2L as follows;

private static final long serialVersionUID = 2L;

As you can see, Exception occures and this time the deserialization didn’t go well.

Exception in thread "main" java.io.InvalidClassException: SerializeMe;
local class incompatible: stream classdesc serialVersionUID = 1,
local class serialVersionUID = 2

How does he know that it changed? If serialVersinUID is static, then it should not have been serialized in the first place, and there should be no information about the previous value 1 during the deserialization. Well, serialVersionUID is an exception to the rule that "static fields don't get serialized". ObjectOutputStream writes every time the value of serialVersionUID to the output stream. ObjectInputStream reads it back and if the value read from the stream does not agree with the serialVersionUID value in the current version of the class, then it throws the InvalidClassException. Moreover, if there is no serialVersionUID declared in the class to be serialized, compiler automatically adds it with a value generated based on the fields declared in the class.

So what is it for after all? Let’s suppose that there is some file storing a serialized object of some class A. The deserialization of that object does not necessarily have to occur exactly after serialization. It can occur after a few months or on a completely different JVM (i.e. sending an object through net using serialization). In both cases, there is a chance that the class declaration has changed between serialization and deserialization. It would be nice to have some kind of versioning system for every serializable class – and serialVersionUID does exactly that. It checks if the data read from the input stream is compatible with the current definition of the class.

If so, then why is it recommended to specify your own serialVersionUID ? It gives us simply more control. Default rules for generating serialVersionUID can be too strict in some cases. For example when the visibility of a field changes, the serialVersionUID changes too. Value generated automatically can differ between various Java implementations. There is a chance that some object serialized on one Java implementation will not deserialize on some other Java implementation, even if the class definition is exactly the same. Furthermore, sometimes you just want for some reason to forbid deserialization of old serialized objects, and in this case you just have to change the serialVersionUID.

Comments

Popular posts from this blog

-- How to Schedule a Task --

How to Connect DataBase to Java Application -JDBC

-- Are you a Android Developer? --