Thứ Ba, 9 tháng 7, 2013

How To Generate SerialVersionUID

There are three ways to generate serialVersionUID for your serialization class.

1. serialver command


JDK has a build in command called “serialver” to generate the serialVersionUID automatically. In this example, you use “serialver” to generate a serialVersionUID for Address class.


E:\workspace\target\classes>serialver Address
Address: static final long serialVersionUID = -687991492884005033L;



2. Use Eclispe IDE


If you are using Eclipse, move your mouse over the serialization class.
serialVersionUID

Or Click on the serialization class and press “CTRL + 1“.

3. Anything you want


Just specify your own serialVersionUID , give a number and append an “L” behind.

private static final long serialVersionUID = 1L;


serialVersionUID in Java Serialization


serialVersionUID is used to ensure that during deserialization the same class (that was used during serialize process) is loaded. This is a one line definition to explain why a serialVersionUID is used?


Apart from the above definition there are quite  a few things to learn from this serialVersionUID. As per javadocs, following is format of serialVersionUID:

serialVersionUID Syntax


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

  • serialVersionUID is a static final field. You can assign any number of your choice to it. Later I will explain the significance of these two statements.


Why serialVersionUID?


Lets start with annoying warning message you get in your IDE when you declare a class as Serializable.
The serializable class Lion does not declare a static final serialVersionUID field of type long

Most of us used to ignore this message as we always do for a warning. My general note is, always pay attention to the java warning messages. It will help you to learn a lot of fundamentals.



serialVersionUID is a must in serialization process. But it is optional for the developer to add it in java source file. If you are not going to add it in java source file, serialization runtime will generate a serialVersionUID and associate it with the class. The serialized object will contain this serialVersionUID along with other data.

Even though serialVersionUID is a static field, it gets serialized along with the object. This is one exception to the general serialization rule that, “static fields are not serialized”.

 

How serialVersionUID is generated?


serialVersionUID is a 64-bit hash of the class name, interface class names, methods and fields. Serialization runtime generates a serialVersionUID if you do not add one in source. Refer this link for the algorithm to generate serialVersionUID.

It is advised to have serialVersionUID as unique as possible. Thats why the java runtime chose to have such a complex algorithm to generate it.

If you want help in generating it, jdk tools provides a tool named serialver. Useserialver -show to start the gui version of the tool as shown below.


How serialVersionUID works?


When an object is serialized, the serialVersionUID is serialized along with the other contents.

Later when that is deserialized, the serialVersionUID from the deserialized object is extracted and compared with the serialVersionUID of the loaded class.

If the numbers do not match then, InvalidClassException is thrown.

If the loaded class is not having a serialVersionUID declared, then it is automatically generated using the same algorithm as before.

Strongly recommended to declare serialVersionUID


Javadocs says,
“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”

Now you know why we should declare a serialVersionUID.

Not only declaring a serialVersionUID is sufficient. You must do the following two things carefully. Otherwise it defeats the purpose of having the serialVersionUID.

serialVersionUID should be maintained. As and when you change anything in the class, you should upgrade the serailVersionUID.
Try your best to declare a unique serialVersionUID.

Demonstrate serialVersionUID


Initial class to be serialized has a serialVersionUID as 1L.










import java.io.Serializable;

 

public class Lion implements Serializable {

 

  private static final long serialVersionUID = 1L;

  private String sound;

 

  public Lion(String sound) {

    this.sound = sound;

  }

 

  public String getSound() {

    return sound;

  }

 

}




Test serialVersionUID:










import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.ObjectInputStream;

import java.io.ObjectOutputStream;

 

public class SerialVersionUIDTest {

 

  public static void main(String args[]) throws IOException, ClassNotFoundException {

    Lion leo = new Lion("roar");

    // serialize

 

    System.out.println("Serialization done.");

    FileOutputStream fos = new FileOutputStream("serial.out");

    ObjectOutputStream oos = new ObjectOutputStream(fos);

    oos.writeObject(leo);

 

    // deserialize

    FileInputStream fis = new FileInputStream("serial.out");

    ObjectInputStream ois = new ObjectInputStream(fis);

    Lion deserializedObj = (Lion) ois.readObject();

    System.out.println("DeSerialization done. Lion: " + deserializedObj.getSound());

  }

}




Output:












Serialization done.

DeSerialization done. Lion: roar




Now change serialVersionUID to 2L in Lion class.










private static final long serialVersionUID = 2L;




Comment the “serialize” block (4 lines of code) in SerialVersionUIDTest. Now run it and you will get the following exception.

  1. Serialized Lion with serialVersionUID with 1L.

  2. Changed serialVersionUID to 2L and compiled and loaded the class.

  3. Deserialize the already serialized object and load it with the latest class.

  4. We get exception as serialVersionUID is not matching.












Exception in thread "main" java.io.InvalidClassException: Lion; local class incompatible: <strong>stream classdesc serialVersionUID = 1, local class serialVersionUID = 2</strong>

  at java.io.ObjectStreamClass.initNonProxy(Unknown Source)

  at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)

  at java.io.ObjectInputStream.readClassDesc(Unknown Source)

  at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)

  at java.io.ObjectInputStream.readObject0(Unknown Source)

  at java.io.ObjectInputStream.readObject(Unknown Source)

  at SerialVersionUIDTest.main(SerialVersionUIDTest.java:21)





 

0 nhận xét:

Đăng nhận xét