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
- All reference classes/objects inside a serializing class/object is serializable
- One or some of the reference classes/objects inside a serializing class/object is NOT serializable
Here, serializing class must implement java.io.Serializable
1. Serialization process:
- During serialization process i.e.; saving state of an Object to File, only instance variables will be participated and persisted to file storage or some other storage via network capability
2. 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
3. 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 in desired format
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 in desired format
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
3.1 When all reference classes/objects inside Customer class is serializable
- Here, both aggregating classes Address and Phone is serializable
- Also main Customer class which has reference to Address/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]]
3.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, NotSerializableException will be thrown at run time, 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
4. 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 also 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
Related Articles:
- Java – Serialization and De-Serialization Tutorial Index
- Java – Introduction to Serialization and De-Serialization
- Java – Serializable interface
- Java – Transient keyword with Serialization
- Java – Transient keyword with static variable in Serialization
- Java – Transient keyword with final variable in Serialization
- Java – Serializing a variable with transient modifier or keyword
- Java – Order of Serialization and De-Serialization
- Java – Serialization with Aggregation
- Java – Serialization with Inheritance
- Java – Externalization in detail
- Java – Serializable v/s Externalizable
- Java – Importance of SerialVersionUID in Serialization
- Java – Singleton Design pattern with Serialization
- Java – How to construct a singleton class in a multi-threaded environment ?
- Java – Singleton design pattern, restricting Object creation by overriding readResolve() method
- Java – How to stop Serialization ?
- Java – How to serialize and de-serialize ArrayList ?
- Java – Interview question & answers on Serialization and Externalization
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
Happy Coding !!
Happy Learning !!