Implementation of readResolve () method for Serializable Singleton Instance

I am trying to write a Serializable Singleton class by adding the readResolve () method. My intention is to get the same object with its state of the object during serialization.

below is my sample code example:

import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; public class SingletonDemo { public static void main(String[] args) { Singleton obj = Singleton.getInstance(); System.out.println("After NEW Object creation : " + obj); obj.i = 5; System.out.println("Object modified"); System.out.println("After Object 1st Modification : " + obj); serializeMe(); System.out.println("Serialized successfully with object state : " + obj); obj.i = 10; System.out.println("Object modified again"); System.out.println("After Object 2nd Modification : " + obj); Singleton st = (Singleton)deSerializeMe(); System.out.println("Deserialized successfully"); System.out.println("After Deserialization : " + st); } public static void serializeMe() { FileOutputStream fos; ObjectOutputStream oos = null; try { oos = new ObjectOutputStream(new FileOutputStream("d:\\SingletonData.txt")); oos.writeObject(Singleton.getInstance()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } public static Object deSerializeMe() { ObjectInputStream oin = null; Object obj = null; try { oin = new ObjectInputStream(new FileInputStream("d:\\SingletonData.txt")); obj = oin.readObject(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } return obj; } } class Singleton implements Serializable { int i; private static Singleton obj = null; private Singleton() { System.out.println("Executing constructor"); i=1; } public static Singleton getInstance() { if(obj == null) { obj = new Singleton(); } System.out.println("An instance is returned"); return obj; } /*private void writeObject(ObjectOutputStream oos) { try { oos.writeInt(i); } catch (Exception e) { e.printStackTrace(); } } private void readObject(ObjectInputStream ois) { try { i = ois.readInt(); } catch (Exception e) { e.printStackTrace(); } }*/ public Object readResolve() { System.out.println("Executing readResolve"); return Singleton.getInstance(); // FIXME } @Override public String toString() { return "Singleton [i=" + i + "]"; } } 

OUTPUT:

 Executing constructor An instance is returned After NEW Object creation : Singleton [i=1] Object modified After Object 1st Modification : Singleton [i=5] An instance is returned Serialized successfully with object state : Singleton [i=5] Object modified again After Object 2nd Modification : Singleton [i=10] Executing readResolve An instance is returned Deserialized successfully After Deserialization : Singleton [i=10] 

I know that the current script will always return the same Singleton instance with the last state of the object.

I tried to override writeObject () and readObject () (commented on this code above), but did not get the desired result. i.e.

 After Deserialization : Singleton [i=5] 

But in readResolve () there is no reference to ObjectInputStream, so I can get the instance and update it using the state of the serialized object before returning.

Please correct me if I am mistaken in my concept and help me solve this problem.

Thanks.

+5
source share
7 answers

Here's how to achieve this:

 public class Singleton implements Serializable { private static Singleton instance = new Singleton(); private int i; public static Singleton getInstance() { return instance; } private Singleton() { } private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { ois.defaultReadObject(); instance = this; } private Object readResolve() { return instance; } public static void main(String[] args) throws Throwable { Singleton s = Singleton.getInstance(); si = 5; ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream(); ObjectOutputStream oos = new java.io.ObjectOutputStream(baos); oos.writeObject(getInstance()); oos.close(); si = 7; //modified after serialization InputStream is = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(is); Singleton deserialized = (Singleton) ois.readObject(); System.out.println(deserialized.i); // prints 5 } 

}

+12
source

The best way to implement Serializable Singleton is to use Enum .

From Joshua Bloch Effective Java:

β€œThis approach is functionally equivalent to the open-source field approach, except that it is more concise, provides a free serializing technique and provides an excellent guarantee against multiple instances even in conditions of complex serialization or Attack reflection . Although this approach has not yet been adopted, a singleton enumeration type is the best way to implement a singleton. "

Save some time and use Enum .

Submit this question for a more detailed discussion of the same topic.

+4
source

try it

  Object readResolve() { Singleton s = getInstance(); si = i; return s; } 

Please note that readResolve should not be publicly available.

+3
source

The solution voted as correct, although it helps in getting the value of "i" on the de-serialized object, it violates the singleton design pattern. After de-serialization, two objects of the "Singleton" class are created.

Proof: modify the main () method as shown below:

 public static void main(String[] args) throws Throwable { Singleton s = Singleton.getInstance(); si = 5; System.out.println("before serialization::"+s.i+" "+ s); //printing value and object ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream(); ObjectOutputStream oos = new java.io.ObjectOutputStream(baos); oos.writeObject(getInstance()); oos.close(); si = 7; //modified after serialization System.out.println("modified after serialization::"+s.i+" "+s); InputStream is = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(is); Singleton deserialized = (Singleton) ois.readObject(); System.out.println("after deserialization::"+deserialized.i+" "+deserialized); //prints 5, but hashCode is different, which means object is not the same } 

Output:

before serialization :: 5 serialization.Singleton@1690726

changed after serialization :: 7 serialization.Singleton@1690726

after deserialization :: 5 serialization.Singleton@1662dc8

Even the second sentence has the same problem. I tried several configurations but nothing worked. Is there any other way to solve this problem?

Please check the Singleton thread to reach a wider audience.

Thanks.

+3
source

This should do the trick (based on your initial question):

  public Object readResolve() { System.out.println("Executing readResolve"); if (obj == null) // optionally use external boolean flag to control this { System.out.println("readResolve - assigned obj = this - loaded state"); obj = this; } return Singleton.getInstance(); } 

If you want to force the Singleton state to load, set obj = null before deserializing the saved state.

Or you can add a boolean flag that tells readResolve() to save or cancel obj .

Be aware of multi-threaded issues if you are working in a multi-threaded environment.

0
source

I believe just returning this to a child class should help

  public Object readResolve() { System.out.println("Executing readResolve"); return this; } 

I know this is a very old post, but I stumbled upon it and others, perhaps, too.

0
source

We can also do this, call the getInstance() method inside readResolve() and save the result in some reference variable of type Singleton then return the link. Make sure that the return type of the method must be of type Object , you can specify any access modifier.

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

Source: https://habr.com/ru/post/1488923/


All Articles