Importance of SerialVersionUID in Serialization

In this article, we will discuss importance of SerialVersionUID in Serialization and De-Serialization process. And finally compare the compiler generated SerialVersionUID v/s programmer defined SerialVersionUID and decide which one to use?

 

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

But there is always serialVersionUID associated with every serializable class.

 

 

If you are using IDE like Eclipse, then it warns with following message

The serializable class <class-name> does not declare static final serialVersionUID field of type long

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 and if it isn’t declared then compiler does the 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, the 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 the 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 the complexity in creating compiler generated serialVersionUID and comparing this unique Id during de-serialization process
  • Programmer has the flexibility of declaring any Long value

 

 

Lets us see a simple demo program for both cases:

Exercise 1: serialVersionUID is same

Below customer class is a serializable class i.e.; it implements java.io.Serializable interface and programmer provides serialVersionUID with value 19L

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 + "]";
	}
}

 

This class is the main class which serializes the 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

 

 

This class de-serializes the Customer class with the 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]

 

 

 

Exercise 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

 

 

References:

https://docs.oracle.com/javase/7/docs/api/java/io/Serializable.html
https://docs.oracle.com/javase/7/docs/platform/serialization/spec/serial-arch.html
https://docs.oracle.com/javase/7/docs/api/java/io/ObjectOutputStream.html
https://docs.oracle.com/javase/7/docs/api/java/io/ObjectInputStream.html
https://docs.oracle.com/javase/7/docs/api/java/io/FileOutputStream.html
https://docs.oracle.com/javase/7/docs/api/java/io/FileInputStream.html
http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.3.1.3

 

Read Also:

 

Happy Coding !!
Happy Learning !!