Saturday, 22 December 2018

Saving Singleton

Protect from reflection


Declare the instance

private constructor set be set public by reflection


 Constructor constructor = ReflectionSingleton.class.getDeclaredConstructor();
// Below code will change constructor access level from private to public

  constructor.setAccessible(true);

// Creating second instance
 ReflectionSingleton instanceTwo = (ReflectionSingleton) constructor.newInstance();


private fields can be accessed by reflection

If you try to protect constructor, by throwing exception like below

     private ReflectionSingleton() {
        if (instance != null) {
            throw new IllegalStateException("instance already created.");
        }
        System.out.println("Singleton instance is being created.");

    }

Private static field's value can also be changed by reflection , like below


Field instance = ReflectionSingleton.class.getDeclaredField("instance");
instance.setAccessible(true); instance.set(instance, null); So apart from above constructor, make the field final, so that its value can not be changed even via reflection private static final ReflectionSingleton instance = new ReflectionSingleton();


Protect from deserialization

The singleton class need to implement(Not override) readResolve()

 protected Object readResolve()
    {
        return instance;
    }

The readResolve method is called when ObjectInputStream has read an object from the stream and is preparing to return it to the caller. ObjectInputStream checks whether the class of the object defines the readResolve method. If the method is defined, the readResolve method is called to allow the object in the stream to designate the object to be returned. The object returned should be of a type that is compatible with all uses. If it is not compatible, a ClassCastException will be thrown when the type mismatch is discovered


Question:
If Object is loaded in a new JVM instance, where static singleton instance field is never initialised, how can it return the "instance" from readResolve().
even when Singlen is loaded and the static field will have the default value null, in lazy initialization strategy, of is eager strategy is used, this can work.

ANSWER:
readResolve() will work, if you try to serialize your already instantiated ("instance") singleton, in same JVM, and in same JVM you try to deserialised, it will return static reference of "instance" variable.

But if in different JVM ?

It seems, during deserialization, the object's would anyway have "instance" variable, which was serialsed and stored in file, same "instance" variable reference will be return.
For now its ok, explore more.



3. CLONING protection

Just throw exception from your singleton class


@Override
  protected Object clone() throws CloneNotSupportedException 
  {
    throw new CloneNotSupportedException();
  }





Sources : 

/DesignPatterns


https://www.geeksforgeeks.org/prevent-singleton-pattern-reflection-serialization-cloning/

No comments:

Post a Comment