Serialization with Aggregation

In this article, we will discuss Serialization with Aggregation i.e.; serializing class contains reference to other classes. It forms a HAS-A relationship

 

There are 2 scenarios with respect to HAS-A relationship

  1. All reference classes/objects inside a serializing class\object is serializable
  2. One or some of the reference classes/objects inside a serializing class\object is NOT serializable

Here, serializing class must implement java.io.Serializable

 

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 to java heap memory

 

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

Serialization with Aggregation

Step 1: Create 2 POJO classes for Address and Phone –> implementing java.io.Serializable interface

  • For any class said to be serializable, if it implement java.io.Serializable interface
  • Otherwise, NotSerializableException will be thrown at run time, although program compiles successfully
  • Both Address & Phone POJO has 2-arg parameterized constructor
  • Overrides toString() method to print values

 

Address.java

package in.bench.resources.serialization.aggregation;

import java.io.Serializable;

class Address implements Serializable {

	// instance variables
	int flatNo;
	String streetName;

	// 2-arg parameterized constructor
	public Address(int flatNo, String streetName) {
		super();
		this.flatNo = flatNo;
		this.streetName = streetName;
	}

	// overriding toString() method
	@Override
	public String toString() {
		return "Address [flatNo=" + flatNo 
				+ ", streetName=" + streetName + "]";
	}
}

 

Phone.java

package in.bench.resources.serialization.aggregation;

import java.io.Serializable;

class Phone implements Serializable {

	// instance variables
	int countryCode;
	int telephoneNumber;

	// 2-arg parameterized constructor
	public Phone(int countryCode, int telephoneNumber) {
		super();
		this.countryCode = countryCode;
		this.telephoneNumber = telephoneNumber;
	}

	// overriding toString() method
	@Override
	public String toString() {
		return "Phone [countryCode=" + countryCode 
				+ ", telephoneNumber=" + telephoneNumber + "]";
	}
}

 

Step 2: Create another POJO class called Customer which will have reference to both Address and Phone classes

That is, Customer class aggregates both Address and Phone classes (HAS-A relationship)

  • For any class said to be serializable, if it implement java.io.Serializable interface
  • Otherwise, NotSerializableException will be thrown at run time, although program compiles successfully
  • Customer POJO has 4-arg parameterized constructor which includes both Address and Phone classes
  • Overrides toString() method to print values

Customer.java

package in.bench.resources.serialization.aggregation;

import java.io.Serializable;

class Customer implements Serializable {

	// instance variables
	int customerId;
	String customerName;
	Address address;
	Phone phone;

	// 4-arg parameterized constructor
	public Customer(int customerId, String customerName,
			Address address, Phone phone) {
		super();
		this.customerId = customerId;
		this.customerName = customerName;
		this.address = address;
		this.phone = phone;
	}

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

 

As we are ready with POJOs, we will begin with our serialization and de-serialization process from main class

 

Step 3: Serialization and De-Serialization (with Aggregation)

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

 

Case 1: When all reference classes/objects inside Customer class is serializable

Here, both aggregating classes Address and Phone is serializable and main class Customer which has reference to Address and Phone is also serializable

SerializationWithAggregation.java

package in.bench.resources.serialization.aggregation;

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

	public static void main(String[] args) {

		// creating address object --> implements java.io.Serializable
		Address address = new Address(402, "2nd street");

		// creating phone object --> implements java.io.Serializable
		Phone phone = new Phone(022, 27759868);

		// creating customer object --> implements java.io.Serializable
		Customer serializeCustomer = 
				new Customer(101, "SJ", address, phone);

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

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

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

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

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

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

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

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

			System.out.println("De-Serialization: Customer object "
					+ "de-serialized from CustomerAggregation.ser file");
		} 
		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 customer values from "
				+ "de-serialized object... \n" + deSerializeCustomer);
	}
}

Output:

Serialization: Customer object saved to CustomerAggregation.ser file

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

Printing customer values from de-serialized object... 
Customer [customerId=101, customerName=SJ, 
address=Address [flatNo=402, streetName=2nd street], 
phone=Phone [countryCode=18, telephoneNumber=27759868]]

 

Case 2: When one or some of the reference classes/objects inside Customer class is NOT serializable

For demo purpose we will remove “implements Serializable” from Address class

Exception: All classes inside Customer class should be serializable, otherwise at run time NotSerializableException will be thrown, although program compiles successfully

Here, Address class doesn’t implement java.io.Serializable interface

Address.java

package in.bench.resources.serialization.aggregation;

class Address {

	// instance variables
	int flatNo;
	String streetName;

	// 2-arg parameterized constructor
	public Address(int flatNo, String streetName) {
		super();
		this.flatNo = flatNo;
		this.streetName = streetName;
	}

	// overriding toString() method
	@Override
	public String toString() {
		return "Address [flatNo=" + flatNo 
				+ ", streetName=" + streetName + "]";
	}
}

 

Note: This program is very same, as that of program 1 or case 1

SerializationWithAggregation.java

package in.bench.resources.serialization.aggregation;

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

	public static void main(String[] args) {

		// creating address object --> implements java.io.Serializable
		Address address = new Address(402, "2nd street");

		// creating phone object --> implements java.io.Serializable
		Phone phone = new Phone(022, 27759868);

		// creating customer object --> implements java.io.Serializable
		Customer serializeCustomer = 
				new Customer(101, "SJ", address, phone);

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

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

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

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

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

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

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

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

			System.out.println("De-Serialization: Customer object "
					+ "de-serialized from CustomerAggregation.ser file");
		} 
		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 customer values from "
				+ "de-serialized object... \n" + deSerializeCustomer);
	}
}

Output:

java.io.NotSerializableException: in.bench.resources.serialization
.aggregation.Address
	at java.io.ObjectOutputStream.writeObject0(Unknown Source)
	at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
	at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
	at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
	at java.io.ObjectOutputStream.writeObject0(Unknown Source)
	at java.io.ObjectOutputStream.writeObject(Unknown Source)
	at in.bench.resources.serialization.aggregation
.SerializationWithAggregation.main(SerializationWithAggregation.java:110)
Printing customer values from de-serialized object... 
null

 

Explanation:

  • JVM throws NotSerializableException for Address class, while serializing Customer class
  • So, it’s very must for every class inside Serializing class to implement java.io.Serializable

 

Case-study: try for Phone class by removing implements Serializable but before that rectify above exception by implementing serializable for Address class

 

Important points to remember while Serialization with Aggregation classes:

  • Rule 1: all classes that need to be serialized must implement java.io.Serializable interface
  • Rule 2: All reference classes inside a serializable class must be java.io.Serializable
  • Rule 3: If any of the class is not implementing java.io.Serializable in the serialization process, then JVM will throw NotSerializableException

 

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 Inheritance
Order of Serialization and De-Serialization