Importance of SerialVersionUID in Serialization

In this article, we will discuss importance of SerialVersionUID in Serialization and De-Serialization process

Finally we will compare compiler generated SerialVersionUID v/s programmer defined SerialVersionUID and decide which one to use ?

In all previous articles, we haven’t discussed anything about serialVersionUID

But there is always serialVersionUID associated with every serializable class

 

Eclipse IDE warning while implementing Serializable interface :

  • If you are using IDE like Eclipse, then it warns with following message
  • Waring : The serializable class <class-name> does not declare static final serialVersionUID field of type long
  • Look at the below screen-capture for message in Eclipse IDE

12_serialversionuid_warning_message

  • As we stated earlier that there is always a serialVersionUID associated with every serializable class, then where we have declared in earlier example ?
  • Serialization: Actually, we haven’t declared this field explicitly and if it isn’t declared then compiler does job for us by declaring this static field and it get saved to serialized file along with Object values
  • De-Serialization: while restoring object back from file storage, then first thing it does is, compare stored serialVersionUID inside serialized file with serializable class
  • Exception: if there is a mismatch between serialVersionUID present in the serialized file and serializable class, then InvalidClassException will be thrown

 

Now, next question with serialVersionUID is whether to use compiler generated serialVersionUID or programmer explicitly declaring serialVersionUID i.e.;

serialVersionUID: Compiler generated v/s programmer defined :

  • Compiler generated serialVersionUID is highly complex as it uses combination of class name and properties to generate this unique Id
  • Due to complexity in creation of this unique Id, performance of serialization and de-serialization process becomes slow
  • Therefore, it is highly recommended to define serialVersionUID inside serializable class and use for both serialization and de-serialization process
  • Firstly it reduces complexity in creating compiler generated serialVersionUID and second comparing this unique Id during de-serialization process
  • Also, programmer hasflexibility of declaring any Long value

Lets us see a simple demo program for both cases:

 

1. serialVersionUID is same

  • Below customer class is a serializable class i.e.; it implements java.io.Serializable interface
  • programmer provides serialVersionUID with value 19L to static variable named serialVersionUID

Customer.java

package in.bench.resources.serial.version.uid;

import java.io.Serializable;

class Customer implements Serializable {

	// default serialVersionUID
	private static final long serialVersionUID = 19L;

	// member variables for Customer
	int customerId;
	String customerName;
	String customerSSN;

	// 3-arg parameterized constructor for Customer
	public Customer(int customerId, String customerName, 
			String customerSSN) {
		super();
		this.customerId = customerId;
		this.customerName = customerName;
		this.customerSSN = customerSSN;
	}

	// to print nicely - customer object
	@Override
	public String toString() {
		return "Customer [customerId=" + customerId 
				+ ", customerName=" + customerName 
				+ ", customerSSN=" + customerSSN + "]";
	}
}

Main class – to Serialize :

  • This class is the main class which serializes Customer class
  • with serialVersionUID 19L

SerializeCustomer.java

package in.bench.resources.serial.version.uid;

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

public class SerializeCustomer {

	public static void main(String[] args) {

		// create a customer object using 3-arg parametrized constructor
		Customer customer = new Customer(101, "SJ", "SSN-109878");

		// creating output stream variables
		FileOutputStream fos = null;
		ObjectOutputStream oos = null;

		try {
			// for writing or saving binary data
			fos = new FileOutputStream("Customer.ser");

			// converting java-object to binary-format 
			oos = new ObjectOutputStream(fos);

			// writing or saving customer object's value to stream
			oos.writeObject(customer);
			oos.flush();
			oos.close();
		} 
		catch (FileNotFoundException fnfex) {
			fnfex.printStackTrace();
		}
		catch (IOException ioex) {
			ioex.printStackTrace();
		}

		System.out.println("Customer object saved to Customer.ser file");
	}
}

Output:

Customer object saved to Customer.ser file

Main class – to DeSerialize :

  • This class de-serializes Customer class with same serialVersionUID used for serialization i.e.; 19L

DeSerializeCustomer.java

package in.bench.resources.serial.version.uid;

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

public class DeSerializeCustomer {

	public static void main(String[] args) {

		// creating input stream variables
		FileInputStream fis = null;
		ObjectInputStream ois = null;

		// creating customer object reference 
		// to hold values after de-serialization 
		Customer customer = null;
		try {
			// reading binary data
			fis = new FileInputStream("Customer.ser");

			// converting binary-data to java-object
			ois = new ObjectInputStream(fis);

			// reading object's value and casting to Customer class
			customer = (Customer) ois.readObject();
		} 
		catch (FileNotFoundException fnfex) {
			fnfex.printStackTrace();
		}
		catch (IOException ioex) {
			ioex.printStackTrace();
		} 
		catch (ClassNotFoundException ccex) {
			ccex.printStackTrace();
		}

		System.out.println("Customer object de-serialized from "
				+ "Customer.ser file\nLet's print to console... \n");

		// printing customer object to console using toString() method
		System.out.println(customer);
	}
}

Output:

Customer object de-serialized from Customer.ser file
Let's print to console... 

Customer [customerId=101, customerName=SJ, customerSSN=SSN-109878]

 

2. serialVersionUID is different

Let us tweak above example by changing serialVersionUID after serialization process

  • We will keep same serialVersionUID i.e.; 19L while serialization
  • Change serialVersionUID after serialization
  • That’s, change to 21L
  • Serialization program will be executed and same output will be seen as per earlier case
  • But during de-serialization process, due to the difference of serialVersionUID, runtime exception will be thrown i.e.; InvalidClassException

Steps:

  • Keep same serialVersionUID (i.e.; 19L) in Customer class and execute serialize customer class
  • Above step help in storing or saving customer object to serialized file
  • Now, change serialVersionUID to 21L in Customer class and compile again
  • Next step, execute de-serialize customer class

Output:

java.io.InvalidClassException: in.bench.resources.serial.version.uid.
Customer; local class incompatible: 
stream classdesc serialVersionUID = 19, local class serialVersionUID = 21
	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 in.bench.resources.serial.version.uid.DeSerializeCustomer.
main(DeSerializeCustomer.java:27)
Customer object de-serialized from Customer.ser file
Let's print to console... 

null

 

Read Also:

 

References:

 

Happy Coding !!
Happy Learning !!

Singleton Design pattern with Serialization
Serializable v/s Externalizable