Serialization with Inheritance

In this article, we will discuss Serialization with Inheritance i.e.; IS-A relationship with inheriting class in detail

 

It’s an easy choice, when both super class & sub class are Serializable, because

  • When super class is serialized, only properties of super class will be serialized
  • When sub class is serialized, properties of sub class as well as inherited properties of super class will also be serialized

 

But we need to understand 2 scenarios with respect to IS-A relationship, while serializing & de-serializing sub class, when

  1. Super class implements java.io.Serializable but sub class doesn’t implement java.io.Serializable
  2. Sub class implements java.io.Serializable but super class doesn’t implement java.io.Serializable

 

Let’s us discuss serialization with inheritance with 2 demo program

Serialization with Inheritance

Case 1: Super class implements java.io.Serializable but sub class doesn’t implement java.io.Serializable

  • When super class is serializable, then any class extending super class will also be serializable by default (inheritance principle)
  • So, here sub class not required to implement java.io.Serializable explicitly
  • When sub class is serialized, then sub class properties as well as inherited super class properties will also be serialized (during serialization process)
  • Note: To prevent sub class from serializing by default, then we need to override writeObject() and readObject() methods

 

Step 1.1: Create super class Customer –> implementing java.io.Serializable interface

  • For any class to be serializable, it must implement java.io.Serializable interface
  • Otherwise, NotSerializableException will be thrown at run time, although program compiles successfully
  • Overrides toString() method to print values

Customer.java

package in.bench.resources.serialization.inheritance;

import java.io.Serializable;

class Customer implements Serializable {

	// instance variables
	int customerId;
	String customerName;

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

 

Step 1.2: Create sub class PrivilegedCustomer –> extending super class Customer

  • For any class to be serializable, it must implement java.io.Serializable interface
  • But here, sub class PrivilegedCustomer is also serializable by default, although sub class doesn’t implement java.io.Serializable interface explicitly
  • Because super class implements serializable interface (inheritance principle)
  • If any class doesn’t implements serializable interface, then NotSerializableException will be thrown at run time, although program compiles successfully
  • Overrides toString() method to print values

PrivilegedCustomer.java

package in.bench.resources.serialization.inheritance;

class PrivilegedCustomer extends Customer {

	// instance variables
	float discountRate;
	int bonusPoints;

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

 

As we are ready with POJOs implementing java.io.Serializable, we will begin with our serialization and de-serialization process from main class

 

Step 1.3: Serialization and De-Serialization (with Inheritance)

For any class to be serializable, it must implement java.io.Serializable interface directly or indirectly though inheritance

Otherwise, NotSerializableException will be thrown at run time, although program compiles successfully

 

To Serialize: any Object, we can use ObjectOutputStream & FileOutputStream to write/save to 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

 

Serializing & De-Serializing sub class PrivilegedCustomer

SerializationWithInheritance.java

package in.bench.resources.serialization.inheritance;

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 SerializationWithInheritance {

	public static void main(String[] args) {

		// creating Privileged Customer object
		PrivilegedCustomer serializePrivilegedCustomer = 
				new PrivilegedCustomer();

		// initialize values for privileged customer object
		serializePrivilegedCustomer.customerId = 101;
		serializePrivilegedCustomer.customerName = "SJ";
		serializePrivilegedCustomer.discountRate = 12.5f;
		serializePrivilegedCustomer.bonusPoints = 1000;

		// time to play with Serialization and De-Serialization process

		// 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 deSerializePrivilegedCustomer = null;

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

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

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

			System.out.println("Serialization: Privileged Customer "
					+ "object saved to CustomerInheritance.ser file\n");

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

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

			// reading object's value and casting to Customer class
			deSerializePrivilegedCustomer = 
					(PrivilegedCustomer) ois.readObject();
			ois.close();

			System.out.println("De-Serialization: "
					+ "Privileged Customer object de-serialized "
					+ "from CustomerInheritance.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 privilege customer values "
				+ "from de-serialized object... \n" 
				+ deSerializePrivilegedCustomer);
	}
}

Output:

Serialization: Privileged Customer object saved to 
CustomerInheritance.ser file

De-Serialization: Privileged Customer object de-serialized 
from CustomerInheritance.ser file

Printing privilege customer values from de-serialized object... 
PrivilegedCustomer [customerId=101, customerName=SJ, 
discountRate=12.5, bonusPoints=1000]

 

Case 2: Sub class implements java.io.Serializable but super class doesn’t implement java.io.Serializable

  • Before moving ahead, we should understand is it possible to serializable sub class, if its super class isn’t serializable?
  • The answer is yes, because if the condition to serialize any class on the basis of its super classes implementing java.io.Serializable interface, then no class in Java can be serialized
  • Reason: java.lang.Object is the base class for any class defined in Java, and it doesn’t implements java.io.Serializable interface
  • In that way, it is very well possible to serialize a sub class even if its super class doesn’t implement java.io.Serializable interface

 

Step 2.1: Create super class Customer –> which doesn’t implement java.io.Serializable interafce

  • For any class to be serializable, it must implement java.io.Serializable interface
  • Otherwise, NotSerializableException will be thrown at run time, although program compiles successfully
  • Overrides toString() method to print values

Customer.java

package in.bench.resources.serialization.inheritance;

class Customer {

	// instance variables
	int customerId;
	String customerName;

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

 

Step 2.2: Create sub class PrivilegedCustomer –> extending super class Customer and also implementing java.io.Serializable interface

  • For any class to be serializable, it must implement java.io.Serializable interface
  • Here, sub class PrivilegedCustomer implement java.io.Serializable interface explicitly and also extends super class Customer
  • If any class doesn’t implements serializable interface, then NotSerializableException will be thrown at run time, although program compiles successfully
  • Overrides toString() method to print values

PrivilegedCustomer.java

package in.bench.resources.serialization.inheritance;

import java.io.Serializable;

class PrivilegedCustomer extends Customer implements Serializable {

	// instance variables
	float discountRate;
	int bonusPoints;

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

 

As we are ready with POJOs implementing java.io.Serializable, we will begin with our serialization and de-serialization process from main class

 

Step 2.3: Serialization and De-Serialization (with Inheritance)

The previous case is very simple like any independent class to serialize in Java. But this case is bit different with respect to serialization and de-serialization process

Serialization process:

  • While serializing sub class, JVM will check if there are any super class which is not implementing java.io.Serializable interface
  • Then, inheriting instance variables of non-serializable super class will be stored to default value ignoring their original values
  • Like 0 for Integer, null for String, etc

De-Serialization process:

  • While de-serializing sub class, JVM will check if there are any non-serializable super class
  • Then, it will execute instance initialization flow (i.e.; similar to object instantiation flow)
  • 1st check: if there are direct initialization at instance variable declaration
  • 2nd check: if there are any initialization block for instance variable assignment
  • 3rd check: invokes no-argument constructor and looks for instance variable assignment
  • To execute the 3rd check, non-serializable super class requires no-argument constructor
  • Exception: otherwise InvalidClassException will be thrown
  • Note: For any other case, constructor is not invoked with only exception being for non-serializable super class

 

Serializing & De-Serializing sub class PrivilegedCustomer

SerializationWithInheritance.java

package in.bench.resources.serialization.inheritance;

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 SerializationWithInheritance {

	public static void main(String[] args) {

		// creating Privileged Customer object
		PrivilegedCustomer serializePrivilegedCustomer = 
				new PrivilegedCustomer();

		// initialize values for privileged customer object
		serializePrivilegedCustomer.customerId = 101;
		serializePrivilegedCustomer.customerName = "SJ";
		serializePrivilegedCustomer.discountRate = 12.5f;
		serializePrivilegedCustomer.bonusPoints = 1000;

		// time to play with Serialization and De-Serialization process

		// 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 deSerializePrivilegedCustomer = null;

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

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

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

			System.out.println("Serialization: Privileged Customer "
					+ "object saved to CustomerInheritance.ser file\n");

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

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

			// reading object's value and casting to Customer class
			deSerializePrivilegedCustomer = 
					(PrivilegedCustomer) ois.readObject();
			ois.close();

			System.out.println("De-Serialization: "
					+ "Privileged Customer object de-serialized "
					+ "from CustomerInheritance.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 privilege customer values "
				+ "from de-serialized object... \n" 
				+ deSerializePrivilegedCustomer);
	}
}

Output:

Serialization: Privileged Customer object saved to 
CustomerInheritance.ser file

De-Serialization: Privileged Customer object de-serialized 
from CustomerInheritance.ser file

Printing privilege customer values from de-serialized object... 
PrivilegedCustomer [customerId=0, customerName=null, 
discountRate=12.5, bonusPoints=1000]

 

Important points to remember while Serialization with Inheritance:

  • If super class implements java.io.Serializable interface, then all sub class is also serializable by default
  • It is possible to serialize sub class, even if its corresponding super class doesn’t implements java.io.Serializable interface
  • While serializing sub class whose super class doesn’t implements io.Serializable interface, then during serialization process inheriting instance variables of non-serializable super class will be stored to default value ignoring their original values (like 0 for Integer, null for String, etc)
  • During de-serialization process, JVM will execute instance initialization flow in 3 steps i.e.;
    1st checks direct variable assignment,
    2nd check inside initialization block and
    3rd check inside no-argument constructor
  • For the 3rd check, it is very must to code a no-argument constructor inside non-serializable super class
  • Otherwise, InvalidClassException will be thrown at run time

 

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

Externalizable interface with example
Serialization with Aggregation