Order of Serialization and De-Serialization

In this article, we will discuss Order of Serialization and De-Serialization and also,

  • Why it is important to know order of serialization
  • What happens, if de-serialize in different order than serialization order
  • What is the readymade solution available from Java to overcome this situation, if we don’t know the order of serialization

 

Serialization process

During serialization process i.e.; saving the state of an Object to File, only instance variables will be participated and persisted to file storage or some other storage via network capability

 

De-Serialization process

During de-serialization process, Object’s state will be restored back from file storage

 

Order of Serialization and De-Serialization

Create 3 POJO classes for Customer, Employee and Student and all implementing java.io.Serializable interface

  • Any class said to be serializable, if it implements java.io.Serializable interface
  • Otherwise, NotSerializableException will be thrown at run time, although program compiles successfully
  • All POJO’s has 2 instance variables & 2-arg parameterized constructor and override toString() method to print values

 

Customer.java

package in.bench.resources.serialization;

import java.io.Serializable;

class Customer implements Serializable {

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

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

	@Override
	public String toString() {
		return "Customer [customerId=" + customerId 
				+ ", customerName=" + customerName + "]";
	}
}

 

Employee.java

package in.bench.resources.serialization;

import java.io.Serializable;

class Employee implements Serializable {

	// member variables for Employee
	int employeeId;
	String employeeName;

	// 2-arg parameterized constructor for Employee
	public Employee(int employeeId, String employeeName) {
		this.employeeId = employeeId;
		this.employeeName = employeeName;
	}

	@Override
	public String toString() {
		return "Employee [employeeId=" + employeeId 
				+ ", employeeName=" + employeeName + "]";
	}
}

 

Student.java

package in.bench.resources.serialization;

import java.io.Serializable;

class Student implements Serializable {

	// member variables for Student
	int studentId;
	String studentName;

	// 2-arg parameterized constructor for Student
	public Student(int studentId, String studentName) {
		this.studentId = studentId;
		this.studentName = studentName;
	}

	@Override
	public String toString() {
		return "Student [studentId=" + studentId 
				+ ", studentName=" + studentName + "]";
	}
}

 

As we are ready with POJOs, we will begin with our serialization and de-serialization in below 3 cases

To Serialize: any Object, we can use ObjectOutputStream & FileOutputStream to write/save to the file (in binary format)

To De-Serialize: any Object, we can use ObjectInputStream & FileInputStream to read/restore from file (which is in binary format) into Java heap memory

 

Program 1: When order of serialization is known, we can de-serialize in same order

Here, we know serialization order so it becomes easy for us to do de-serialization

OrderOfSerializationDeSerialization.java

package in.bench.resources.serialization;

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

public class OrderOfSerializationDeSerialization {

	public static void main(String[] args) {

		Customer customer = new Customer(101, "Jeremy Krist");
		Employee employee = new Employee(111, "Mike Gentry");
		Student student = new Student(121, "Azeem Sayed");

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

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

		// creating customer object reference 
		// to hold values after de-serialization 
		Customer deSerializeCustomer = null;
		Employee deSerializeEmployee = null;
		Student deSerializeStudent = null;

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

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

			// writing or saving customer object's value to stream
			oos.writeObject(customer);
			oos.writeObject(employee);
			oos.writeObject(student);
			oos.flush();
			oos.close();

			System.out.println("Serialization: All objects "
					+ "saved to OrderOfObjects.ser file\n");

			// reading binary data
			fis = new FileInputStream("OrderOfObjects.ser");

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

			// reading object's value and casting to respective class
			deSerializeCustomer = (Customer) ois.readObject();
			deSerializeEmployee = (Employee) ois.readObject();
			deSerializeStudent = (Student) ois.readObject();
			ois.close();

			System.out.println("De-Serialization: All objects "
					+ "de-serialized from OrderOfObjects.ser file\n");
		} 
		catch (FileNotFoundException fnfex) {
			fnfex.printStackTrace();
		}
		catch (IOException ioex) {
			ioex.printStackTrace();
		}
		catch (ClassNotFoundException ccex) {
			ccex.printStackTrace();
		}

		// printing customer object to console using toString() method
		System.out.println("Printing values "
				+ "from de-serialized object... \n");
		System.out.println(deSerializeCustomer);
		System.out.println(deSerializeEmployee);
		System.out.println(deSerializeStudent);
	}
}

Output:

Serialization: All objects saved to OrderOfObjects.ser file

De-Serialization: All objects de-serialized from OrderOfObjects.ser file

Printing values from de-serialized object... 

Customer [customerId=101, customerName=Jeremy Krist]
Employee [employeeId=111, employeeName=Mike Gentry]
Student [studentId=121, studentName=Azeem Sayed]

 

Program 2: De-serialization is done in different than serialization order

In this program, irrespective of whether we know serialization order or NOT, we will perform de-serialization in some random order

 

Let’s see what happens, if we change the de-serialization order (other than from serialization order)

Serializing order

  1. Customer
  2. Employee
  3. Student

De-Serializing order

  1. Student
  2. Customer
  3. Employee

 

OrderOfSerializationDeSerialization.java

package in.bench.resources.serialization;

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

public class OrderOfSerializationDeSerialization {

	public static void main(String[] args) {

		Customer customer = new Customer(101, "Jeremy Krist");
		Employee employee = new Employee(111, "Mike Gentry");
		Student student = new Student(121, "Azeem Sayed");

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

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

		// creating customer object reference 
		// to hold values after de-serialization 
		Customer deSerializeCustomer = null;
		Employee deSerializeEmployee = null;
		Student deSerializeStudent = null;

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

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

			// writing or saving customer object's value to stream
			oos.writeObject(customer);
			oos.writeObject(employee);
			oos.writeObject(student);
			oos.flush();
			oos.close();

			System.out.println("Serialization: All objects "
					+ "saved to OrderOfObjects.ser file\n");

			// reading binary data
			fis = new FileInputStream("OrderOfObjects.ser");

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

			// reading object's value and casting to respective class
			deSerializeStudent = (Student) ois.readObject();
			deSerializeCustomer = (Customer) ois.readObject();
			deSerializeEmployee = (Employee) ois.readObject();
			ois.close();

			System.out.println("De-Serialization: All objects "
					+ "de-serialized from OrderOfObjects.ser file\n");
		} 
		catch (FileNotFoundException fnfex) {
			fnfex.printStackTrace();
		}
		catch (IOException ioex) {
			ioex.printStackTrace();
		}
		catch (ClassNotFoundException ccex) {
			ccex.printStackTrace();
		}

		// printing customer object to console using toString() method
		System.out.println("Printing values"
				+ " from de-serialized object... \n");
		System.out.println(deSerializeCustomer);
		System.out.println(deSerializeEmployee);
		System.out.println(deSerializeStudent);
	}
}

Output:

Serialization: All objects saved to OrderOfObjects.ser file

Exception in thread "main" java.lang.ClassCastException: in.bench.resources
.serialization.Customer cannot be cast to 
in.bench.resources.serialization.Student
	at in.bench.resources.serialization.OrderOfSerializationDeSerialization
.main(OrderOfSerializationDeSerialization.java:109)

 

Explanation:

  • Here serialization order is Customer –> Employee –> Student
  • But we are de-serializing in different order i.e.; Student –> Customer –> Employee
  • So, while de-serializing 1st time when we read object from serialized file, it returns Customer object, as we serialized Customer object first
  • But instead of type-casting to Customer object, we type-casted to Student object –> which results in throwing java.lang.ClassCastException
  • To overcome this exception, we can use instanceOf operator
  • Move to program 3 –> for much improved version using instanceOf operator

 

Program 3: When order of serialization is unknown, how can we overcome this situation?

We can use instanceOf operator to check the respective object first iterating through while loop

Later, we can assign it to correct class by type-casting

Note: here, program will throw java.io.EOFException for condition checked inside parenthesis of while loop

But we can catch this exception and take corrective action (like here, we can print “End of file message” to console)

OrderOfSerializationDeSerialization.java

package in.bench.resources.serialization;

import java.io.EOFException;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class OrderOfSerializationDeSerialization {

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

		Customer customer = new Customer(101, "Jeremy Krist");
		Employee employee = new Employee(111, "Mike Gentry");
		Student student = new Student(121, "Azeem Sayed");

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

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

		// creating customer object reference 
		// to hold values after de-serialization 
		Customer deSerializeCustomer = null;
		Employee deSerializeEmployee = null;
		Student deSerializeStudent = null;

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

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

			// writing or saving customer object's value to stream
			oos.writeObject(customer);
			oos.writeObject(employee);
			oos.writeObject(student);
			oos.flush();
			oos.close();

			System.out.println("Serialization: All objects "
					+ "saved to OrderOfObjects.ser file\n");

			// reading binary data
			fis = new FileInputStream("OrderOfObjects.ser");

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

			// temp Object variable
			Object object = null;

			// iterating, reading & casting to respective class 
			while((object = ois.readObject()) != null){
				if(object instanceof Customer)
					deSerializeCustomer = (Customer) object;
				else if(object instanceof Employee)
					deSerializeEmployee = (Employee) object;
				else if(object instanceof Student)
					deSerializeStudent = (Student) object;
			} // END of while loop
		} 
		catch (EOFException eofex) {
			// eofex.printStackTrace();
			System.out.println("De-Serialization: All objects "
					+ "de-serialized from OrderOfObjects.ser file\n");
			System.out.println("End of file reached...\n");
		}
		catch (FileNotFoundException fnfex) {
			fnfex.printStackTrace();
		}
		catch (IOException ioex) {
			ioex.printStackTrace();
		}
		catch (ClassNotFoundException ccex) {
			ccex.printStackTrace();
		}
		finally {
			ois.close(); // closing stream
		}

		// printing customer object to console using toString() method
		System.out.println("Printing values "
				+ "from de-serialized object... \n");
		System.out.println(deSerializeCustomer);
		System.out.println(deSerializeEmployee);
		System.out.println(deSerializeStudent);
	}
}

Output:

Serialization: All objects saved to OrderOfObjects.ser file

De-Serialization: All objects de-serialized from OrderOfObjects.ser file

End of file reached...

Printing values from de-serialized object... 

Customer [customerId=101, customerName=Jeremy Krist]
Employee [employeeId=111, employeeName=Mike Gentry]
Student [studentId=121, studentName=Azeem Sayed]

 

Important points about Serialization Order:

  • Rule 1: all classes that need to be serialized must implement java.io.Serializable interface
  • Order of Serialization is very important to know, because we need to follow the same order while de-serializing the objects
  • If the Order of Serialization is unknown, then it may throw java.lang.ClassCastException
  • To overcome ClassCastException, we can 1st check type of object using instanceOf operator and then assign it to proper class after doing necessary type-casting
  • Exception: iterating through while loop may throw EOFException, we need catch this exception and handle it properly

 

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 !!

Serialization with Aggregation
Serializing a variable with transient modifier or keyword