0
Sponsored Links


Ad by Google
In java all the Serializable classes are automatically given a unique identifier if you explicitly not defined. The unique identifier of the class is maintained by serialVersionUID field. So the serialVersionUID is a unique identifier of the serializable classes, and the value of serialVersionUID is used at the time of de-serialization to verify that the sender and receiver of a serialized object have loaded a class for that object that are compatible with respect to serialization.

The default value of serialVersionUID is computed based on your class's field, method, interfaces etc. It may be vary from environment to environment or compiler to compiler. That's why you always need to define explicitly the value of serialVersionUID. It's better to redefine the value of serialVersionUID each time you changed the structure of your class.

Syntax to define serialVersionUID:

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


There is a tool inside JDK to generate the serialVersionUID value, If you wish to see the serialVersionUID value of serializable classes, for example String is a serializable class and the value of serialVersionUID of String class can be seen by following the below given steps.
  • Open a command prompt and go to the bin directory of your installed JDK, for example: C:\Program Files\Java\jdk1.7.0_45\bin
  • Type: serialver -show at your command prompt.
  • This will open a window, type the java.lang.String in Full class name field and click on show button. It will display the serialVersionUID value in below field corresponding to serialVersionUID label. see the screen shot.


Strongly Recommendation, copied from java doc.
  • 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.

At the time of de-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 it will throws a InvalidClassException.

Let's see the the impact of serialVersionUID practically.
Product.java

package com.javamakeuse.poc;

import java.io.Serializable;

public class Product implements Serializable {
 private String productName;

 public String getProductName() {
  return productName;
 }

 public void setProductName(String productName) {
  this.productName = productName;
 }

}

Now serialized the Product object in SerialVersionTest.java class.

package com.javamakeuse.poc;

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

public class SerialVersionTest {

 private static String file = "product.ser";

 private static void serialized(Object obj) throws IOException {
  FileOutputStream fos = new FileOutputStream(file);
  ObjectOutputStream out = new ObjectOutputStream(fos);
  out.writeObject(obj);
  out.close();
 }

 public static void main(String[] args) {
  Product product = new Product();
  product.setProductName("pendrive");
  try {
   serialized(product);
  } catch (IOException e) {
   e.printStackTrace();
  }
 }
}

Run SerialVersionTest.java class, It will serialized the product object and create a product.ser file. Now add a productPrice field in Product.java class.

package com.javamakeuse.poc;

import java.io.Serializable;

public class Product implements Serializable {
 private String productName;

 // added new field
 private double productPrice;

 public String getProductName() {
  return productName;
 }

 public void setProductName(String productName) {
  this.productName = productName;
 }

 public double getProductPrice() {
  return productPrice;
 }

 public void setProductPrice(double productPrice) {
  this.productPrice = productPrice;
 }

}

Now, Restore(De-Serialized) the object from the serialized object. Here is a SerialVersionTest.java class to De-Serialized the stream.

package com.javamakeuse.poc;

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

public class SerialVersionTest {

 private static String file = "product.ser";
 
 private static void deSerialized() throws IOException, ClassNotFoundException{
  FileInputStream fis= new FileInputStream(file);
  ObjectInputStream in = new ObjectInputStream(fis);
  
  Product product = (Product)in.readObject();
  in.close();
  //printing product name
  System.out.println(product.getProductName());
  
 }
 public static void main(String[] args) {
  try {
   deSerialized();
  } catch (IOException | ClassNotFoundException e) {
   e.printStackTrace();
  }
 }
}

OUT PUT:
java.io.InvalidClassException: com.javamakeuse.poc.Product; local class incompatible: stream classdesc serialVersionUID = 2360281018254192478, local class serialVersionUID = 7079879676188092747
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:604)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1601)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1514)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1750)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1347)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:369)
at com.javamakeuse.poc.SerialVersionTest.deSerialized(SerialVersionTest.java:15)
at com.javamakeuse.poc.SerialVersionTest.main(SerialVersionTest.java:22)


The InvalidClassException occurred because all the serializable classes are automatically given a unique identifier(serialVersionUID). If the identifier of the class does not equal to serialized object, It will throws InvalidClassException. The unique identifier of the class is maintained by serialVersionUID field. The default value of serialVersionUID is hash code of the object. You can control the versioning by providing the serialVersionUID field manually and make sure that the value of serialVersionUID always the same.

For example,

package com.javamakeuse.poc;

import java.io.Serializable;

public class Product implements Serializable {

 private static final long serialVersionUID = 123L;

 private String productName;

 public String getProductName() {
  return productName;
 }

 public void setProductName(String productName) {
  this.productName = productName;
 }

}

Now serialized the Product object by running SerialVersionTest.java class, Once serialization is done add a productPrice in the Product class.

Updated Product.java:

package com.javamakeuse.poc;

import java.io.Serializable;

public class Product implements Serializable {

 private static final long serialVersionUID = 123L;

 private String productName;

 // added new field after serialized the product obj.
 private double productPrice;

 public String getProductName() {
  return productName;
 }

 public void setProductName(String productName) {
  this.productName = productName;
 }

 public double getProductPrice() {
  return productPrice;
 }

 public void setProductPrice(double productPrice) {
  this.productPrice = productPrice;
 }

}

We have added a new field in Product.java class after serialization but we have not changed the serialVersionUID, so now restoring(de-serialized) of object will not throws any exception and work perfect.
Test the program:

package com.javamakeuse.poc;

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

public class SerialVersionTest {

 private static String file = "product.ser";

 private static void deSerialized() throws IOException,
   ClassNotFoundException {
  FileInputStream fis = new FileInputStream(file);
  ObjectInputStream in = new ObjectInputStream(fis);
  
  Product product = (Product) in.readObject();
  in.close();
  
  System.out.println(product.getProductName());

 }

 public static void main(String[] args) {
  try {
   deSerialized();
  } catch (IOException | ClassNotFoundException e) {
   e.printStackTrace();
  }
 }
}

Run the program you will get the expected output.
OUT PUT: pendrive

That's it.

References:
Reference 1
Reference 2


Sponsored Links

0 comments:

Post a Comment