How to deal with Singleton along with Serialization

Viewed 58789

Consider I have a Singleton class defined as follows.

public class MySingleton implements Serializable{
 private static MySingleton myInstance;

 private MySingleton(){

 }
  static{
    myInstance =new MySingleton();
 }
 public static MySingleton getInstance(){
    return MySingleton.myInstance;
 }
}

The above definition according to me satisfies the requirements of a Singleton.The only additional behaviour added is that the class implements serializable interface.

If another class X get the instance of the single and writes it to a file and at a later point deserializes it to obtain another instance we would have two instances which is against the Singleton principle.

How can I avoid this or am I wrong in above definition itself.

9 Answers

Here below is my Singleton class that implements Serializable interface. Mark that it contains readResolve() method also.

import java.io.Serializable;

public class Singleton implements Serializable {

    private static Singleton singleton = new Singleton( );

    public int i = 1;

    private Singleton() { }

    public static Singleton getInstance( ) {

       return singleton;
    }

    public Object readResolve() {
       return getInstance( );
    }

    public static void main(String[] args) {
        Singleton s1 = getInstance();
        System.out.println(s1.hashCode());

        Singleton s2 = getInstance();
        System.out.println(s2.hashCode());
    }
}

Below is the class that will first serialize and then deserialize the above class. Here deserialization takes place two times, but both time only one instance will be created because of readResolve() method.

public class SingletonSerializableDemo {

    static Singleton sing = Singleton.getInstance();
    static Singleton s1  = null;
    static Singleton s2 = null;
    public static void main(String[] args) {
        try {
             FileOutputStream fileOut =
             new FileOutputStream("E:/singleton.ser");
             ObjectOutputStream out = new ObjectOutputStream(fileOut);
             out.writeObject(sing);
             out.close();
             fileOut.close();
             System.out.println("Serialized data is saved");

             FileInputStream fileIn1 = new FileInputStream("E:/singleton.ser");
             FileInputStream fileIn2 = new FileInputStream("E:/singleton.ser");
             ObjectInputStream in1 = new ObjectInputStream(fileIn1);
             ObjectInputStream in2 = new ObjectInputStream(fileIn2);
             s1 = (Singleton) in1.readObject();
             s2 = (Singleton) in2.readObject();
             System.out.println(s1.hashCode() + " "+ s1.i);
             s1.i = 10;
             System.out.println(s2.hashCode() + " "+ s2.i);
             in1.close();
             in2.close();
             fileIn1.close();
             fileIn2.close();
          }catch(Exception i) {
             i.printStackTrace();
          }
    }
}

And the output will be:

Serialized data is saved
21061094 1
21061094 10

Conclusion: Singleton class can also be serialized by keeping readResolve() method in the Singleton class.

Here is the Answer for Breaking the Singleton class and and how to prevent our class from creating different object by using readResolve() methood;

import java.io.Serializable;

public class Singleton implements Serializable {

private static final long serialVersionUID = 1L;

private Singleton() {
}

private static class SingletonHelper {

    private static final Singleton INSTANCE = new Singleton();

}

public static Singleton getInstance() {

    return SingletonHelper.INSTANCE;
}

private Object readResolve() {
    Singleton instance = getInstance();
    return instance;
}

}

public class BreakSIngletonUsingSerialization {

public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {

    Singleton demo1 =Singleton.getInstance();
    ObjectOutput out = new ObjectOutputStream(new FileOutputStream("C:/Eclipse/serial.ser"));
    out.writeObject(demo1);
    Singleton demo2 =null;
    ObjectInput in = new ObjectInputStream(new FileInputStream("C:/Eclipse/serial.ser"));

    demo2 = (Singleton)in.readObject();

    System.out.println("Hascode demo1 : " +demo1);
    System.out.println("Hascode demo2 : " +demo2);
}

}

Related