July 31, 2022

Serialization in Java With Examples

Serialization in Java is the process of converting state of the object into a byte stream and the reverse process of deserialization converts that byte stream (serialized form of object) back into a copy of the object.

Once the object is converted into byte stream you can save it. Because of this ability to persist an object, provided by serialization in Java, objects we create could exist beyond the lifetime of the JVM.

Following image shows the process of serialization and deserialization in Java and what can you do with serialized object.

What is required for serialization

A Java object can be serialized if its class or any of its superclasses implements either the java.io.Serializable interface or its subinterface, java.io.Externalizable. Note that Serializable is a marker interface and does not have any field or method.

ObjectOutputStream and ObjectInputStream classes

For serializing an object writeObject() method of the ObjectOutputStream class is used.

final void writeObject(Object obj) throws IOException

For deserializing an object readObject() method of the ObjectInputStream class is used.

final Object readObject() throws IOException, ClassNotFoundException

Java object serialization example

For the example we’ll use the following Employee class that implements Serializable interface. Getters and Setters not included in the code here.

import java.io.Serializable;

public class Employee implements Serializable{
  private String name;
  private String dept;
  private int salary;
  private transient int ssn;
  Employee(String name, String dept, int salary, int ssn){
    this.name = name;
    this.dept = dept;
    this.salary = salary;
    this.ssn = ssn;
  }
}

As you can see class implements Serializable interface, which is a must requirement for serialization. Trying to serialize an object where class in not implementing Serializable interface results in java.io.NotSerializableException.

By default all the non-static object fields are serialized. If you don’t want any specific field to be serialized then the field should be marked transient. In the class SSN field is marked as transient.

Serialization process
public class SerializationDemo {
  public static void main(String[] args) {
    Employee emp = new Employee("Ryan", "IT", 7500, 11111);
    final String fileName = "F:\\knpcode\\emp.ser";
    serialzeObject(emp, fileName);
  }

  // Method to serialize object
  public static void serialzeObject(Object obj, String fileName){
    try(ObjectOutputStream outStream = new ObjectOutputStream(new FileOutputStream(fileName))){
      outStream.writeObject(obj);	   
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
}

On executing this program a file called emp.ser is created that stores the serialized information of the Employee object.

Deserialization process

Following program deserializes the Employee object serialized in the above example.

public class SerializationDemo {

  public static void main(String[] args) {
    //Employee emp = new Employee("Ryan", "IT", 7500, 11111);
    final String fileName = "F:\\knpcode\\emp.ser";
    //serialzeObject(emp, fileName);
    /// Do null check here
    Employee e = (Employee)deSerializeObject(fileName);
    System.out.println("Name- " + e.getName());
    System.out.println("Dept- " + e.getDept());
    System.out.println("Salary- " + e.getSalary());
    System.out.println("SSN- " + e.getSsn());
  }

  // Method to deserialize object
  public static Object deSerializeObject(String fileName){
    Object obj = null;
    try(ObjectInputStream inStream = new ObjectInputStream(new FileInputStream(fileName))){
      obj = inStream.readObject();	 			
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (ClassNotFoundException e) {
      System.out.println("No class found for serialization");
      e.printStackTrace();
    }
    return obj;
  }
}
Output
Name- Ryan
Dept- IT
Salary- 7500
SSN- 0

In the deserialization program, file storing the serialized object is passed to the ObjectInputStream. From that object is read using readObject() method.

Since SSN is marked as transient so SSN field was not serialized while serializing the object. That is why there is not data to read for SSN field so the default int value 0 is displayed.

Points about Serialization

  1. The object to be persisted must implement the Serializable interface or inherit that implementation from its parent class. Though the reverse is not true if child class implements Serializable then parent class doesn’t become Serializable.
  2. All nonserializable fields should be marked transient.
  3. If a class that implements Serializable references another object then that object should also be implementing Serializable in order to be serialized. If all the referenced objects also implement Serializable interface then the whole object graph is serialized.
  4. In deserialization process object is reconstituted from the serialized bytes so no constructor is called during the process of deserialization.

Implementing writeObject() and readObject() methods

Most of the time default implementation of writeObject() and readObject() methods work for serializing and deserializing an object but you can also implement these methods to have more control over the process.

One such scenario is when parent class doesn’t implement Serializable interface where as the child class do. While serializing the object if you want to serialize fields inherited from parent class then you can do that by implementing writeObject() and readObject() methods. Let’s understand it with an example, parent class is ClassA extended by ClassB.

public class A {
  int a;
  public int getA() {
    return a;
  }
  public void setA(int a) {
    this.a = a;
  } 	
}
import java.io.Serializable;

public class B extends A implements Serializable{
  int b;
  String test;
  public int getB() {
    return b;
  }
  public void setB(int b) {
    this.b = b;
  }
  public String getTest() {
    return test;
  }
  public void setTest(String test) {
    this.test = test;
  }
	
  public static void main(String[] args) {
    B obj = new B();
    obj.setA(1);
    obj.setB(2);
    obj.setTest("Test");
    final String fileName = "F:\\knpcode\\test.ser";	
    SerializationDemo.serialzeObject(obj, fileName);
    
    B retObj = (B)SerializationDemo.deSerializeObject(fileName);
    System.out.println("A " + retObj.getA());
    System.out.println("B " + retObj.getB());
    System.out.println("Test " + retObj.getTest());
  }
}
Output
A 0
B 2
Test Test

As you can see value for field A is 0. Field A is not serialized because ClassA doesn’t implement Serializable. You can implement writeObject() and readObject() methods and provide logic to explicitly serialize and deserialize fields inherited from parent class in this scenario.

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class B extends A implements Serializable{
  int b;
  String test;
  public int getB() {
    return b;
  }
  public void setB(int b) {
    this.b = b;
  }
  public String getTest() {
    return test;
  }
  public void setTest(String test) {
    this.test = test;
  }

  public static void main(String[] args) {
    B obj = new B();
    obj.setA(1);
    obj.setB(2);
    obj.setTest("Test");
    final String fileName = "F:\\knpcode\\test.ser";	
    SerializationDemo.serialzeObject(obj, fileName);
    
    B retObj = (B)SerializationDemo.deSerializeObject(fileName);
    System.out.println("A " + retObj.getA());
    System.out.println("B " + retObj.getB());
    System.out.println("Test " + retObj.getTest());
  }
	
  private void writeObject(ObjectOutputStream outStream) throws IOException{
    // default functionality for classB
    outStream.defaultWriteObject();
    // Explicitly writing ClassA fields
    outStream.writeInt(getA());
  }

  private void readObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException{
    // default functionality for classB
    inputStream.defaultReadObject();
    // Explicitly reading ClassA fields and setting them
    setA(inputStream.readInt());
  }
}

Using writeObject() and readObject() to stop serialization

You may also have a scenario where you want to ensure that your class is never serialized.

Let's say you create a class whose superclass is serializable but you do not want that new class to be serializable? Since the parent class is serializable so child class is automatically serializable.

To ensure that child class is not serializable you can implement writeObject() and readObject() methods and throw NotSerializableException from the methods.

In the example ClassA is the parent class which implements Serializable.

public class A implements Serializable{
  int a;
  public int getA() {
    return a;
  }
  public void setA(int a) {
    this.a = a;
  } 	
}

ClassB is the child class with writeObject() and readObject() methods implemented to throw NotSerializableException.

import java.io.IOException;
import java.io.NotSerializableException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class B extends A{
  int b;
  String test;
  public int getB() {
    return b;
  }
  public void setB(int b) {
    this.b = b;
  }
  public String getTest() {
    return test;
  }
  public void setTest(String test) {
    this.test = test;
  }
	
  public static void main(String[] args) {
    B obj = new B();
    obj.setA(1);
    obj.setB(2);
    obj.setTest("Test");
    final String fileName = "F:\\knpcode\\test.ser";	
    SerializationDemo.serialzeObject(obj, fileName);
    
    B retObj = (B)SerializationDemo.deSerializeObject(fileName);
    System.out.println("A " + retObj.getA());
    System.out.println("B " + retObj.getB());
    System.out.println("Test " + retObj.getTest());
  }

  private void writeObject(ObjectOutputStream outStream) throws IOException{
    throw new NotSerializableException("Class is not serializable");
  }
   
  private void readObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException{
    throw new NotSerializableException("Class is not serializable");
  }
}
Output
java.io.NotSerializableException: Class is not serializable
	at com.knpcode.proj.Programs.B.writeObject(B.java:40)

That's all for the topic Serialization in Java With Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

No comments:

Post a Comment