Serialization Safe Singleton Object

In modern-day distributed system architecture, applications and databases are configured over geographical locations. Hence java Objects need to be transferred over the network as well.

Java object directly cannot be streamed directly, it needs to be converted to a byte stream. The conversion of states of an object into byte stream is called Serialization.
The conversion of a byte stream back into a java object is called Deserialization.

Serialization and Deserialization process majorly used in Hibernate, RMI, JPA, EJB and JMS technologies.

Singleton objects also can be serialized and deserialized but a deserialized instance will be different from the serialized object, this process will create multiple copies of a singleton object as shown below.
 

package org.wesome.dsalgo.design.pattern.singleton;

import java.io.Serializable;
import java.util.Objects;

public class Apple implements Cloneable, Serializable {
    static Apple appleInstance;

    private Apple() {
        System.out.println("Apple default constructor");
    }

    public static Apple getAppleInstance() {
        System.out.println("Apple getAppleInstance");
        if (Objects.isNull(appleInstance)) {
            synchronized (Apple.class) {
                if (Objects.isNull(appleInstance)) {
                    appleInstance = new Apple();
                }
            }
        }
        return appleInstance;
    }

    public Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException("Object cannot be cloned.");
    }
}
package org.wesome.dsalgo.design.pattern.singleton;

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

public class SingletonClass {
    public static void main(String[] args) {
        Apple apple = Apple.getAppleInstance();
        System.out.println("apple = " + apple);
        serializeObject(apple);
        Apple apple1 = deSerializeObject();
        System.out.println("apple1 = " + apple1);
    }

    private static void serializeObject(Apple apple) {
        System.out.println("ObjectCreation.serializeObject");
        try {
            FileOutputStream fileOut = new FileOutputStream("Apple.ser");
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOut);
            objectOutputStream.writeObject(apple);
            objectOutputStream.close();
            fileOut.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static Apple deSerializeObject() {
        System.out.println("ObjectCreation.deSerializeObject");
        Apple apple = null;
        try {
            FileInputStream fileIn = new FileInputStream("Apple.ser");
            ObjectInputStream objectInputStream = new ObjectInputStream(fileIn);
            apple = (Apple) objectInputStream.readObject();
            objectInputStream.close();
            fileIn.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return apple;
    }
}
plugins {
    id 'java'
    id "io.freefair.lombok" version "6.4.1"
}

group = 'org.wesome'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = JavaVersion.VERSION_1_8

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
}

dependencies {
    testImplementation 'org.junit.jupiter:junit-jupiter:5.6.2'
}

test {
    useJUnitPlatform()
}

 

Serializable and Externalizable interface helps object to transfer the class and object over the network, a readResolve method always makes sure the object return from the class should also be resolved from the network only.

The readResolve method is called just before the time of deserialization, ObjectInputStream has read an object from the network. The ObjectInputStream checks if the class of the object has implemented the readResolve method. If the method is defined in the class, the readResolve method is called which will resolve the object of the class from the network only as shown below.

package org.wesome.dsalgo.design.pattern.singleton;

import java.io.Serializable;
import java.util.Objects;

public class Apple implements Cloneable, Serializable {
    static Apple appleInstance;

    private Apple() {
        System.out.println("Apple default constructor");
    }

    public static Apple getAppleInstance() {
        System.out.println("Apple getAppleInstance");
        if (Objects.isNull(appleInstance)) {
            synchronized (Apple.class) {
                if (Objects.isNull(appleInstance)) {
                    appleInstance = new Apple();
                }
            }
        }
        return appleInstance;
    }

    protected Object readResolve() {
        return getAppleInstance();
    }

    public Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException("Object cannot be cloned.");
    }
}
package org.wesome.dsalgo.design.pattern.singleton;

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

public class SingletonClass {
    public static void main(String[] args) {
        Apple apple = Apple.getAppleInstance();
        System.out.println("apple = " + apple);
        serializeObject(apple);
        Apple apple1 = deSerializeObject();
        System.out.println("apple1 = " + apple1);
    }

    private static void serializeObject(Apple apple) {
        System.out.println("ObjectCreation.serializeObject");
        try {
            FileOutputStream fileOut = new FileOutputStream("Apple.ser");
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOut);
            objectOutputStream.writeObject(apple);
            objectOutputStream.close();
            fileOut.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static Apple deSerializeObject() {
        System.out.println("ObjectCreation.deSerializeObject");
        Apple apple = null;
        try {
            FileInputStream fileIn = new FileInputStream("Apple.ser");
            ObjectInputStream objectInputStream = new ObjectInputStream(fileIn);
            apple = (Apple) objectInputStream.readObject();
            objectInputStream.close();
            fileIn.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return apple;
    }
}
plugins {
    id 'java'
    id "io.freefair.lombok" version "6.4.1"
}

group = 'org.wesome'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = JavaVersion.VERSION_1_8

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
}

dependencies {
    testImplementation 'org.junit.jupiter:junit-jupiter:5.6.2'
}

test {
    useJUnitPlatform()
}

 

follow us on