Tuesday, July 9

Effective java Item 77: For instance control, prefer enum types to readResolve




                      For instance control, prefer enum types to readResolve

What is instance control?

Instance control basically refers to single instance of the class OR singleton design pattern .

Java 1.5 onwards we should always prefer ENUM to create singleton instance. It is absolutely safe . JVM guarantees that. All earlier mechanical of controlling instance to single are already broken.

So in any interview you can confidently say ENUM= provides perfect singleton implementation .

Now what is readResolve?

readResolve is nothing but a method provided in serializable class . This method is invoked when serialized object is deserialized. Through readResolve method you can control how instance will be created at the time of deserialization.Lets try to understand some code

public class President {
private static final President singlePresident = new President();

private President(){
}
}

This class generates single instance of President class. singlePresident is static instance and same will be used across.  

But do you see it breaks anywhere?

Implement this class with Serializable interface and our instance control strategy to single instance will immediately fail. At deserialization time brand new instance will be created thus we are no longer restricting single instance.

Is there a way to control that.. Let’s try.

public class President implements Serializable {
private static final President singlePresident = new President();

private President(){
}

Private Object readResolve(){

return singlePresident;
}
}

What did we do? 
We controlled the deserialization mechanism through readResolve method. We are returning the same instance what was created at the time of serialization Or when President was instantiated at first place. So the instance remains the same.

So can we say readResolve() method is sufficient to control the instance creation??

 Lets have a deeper look :


We need to understand that before readResolve() method returns singlePresident , an instance of President is created during normal deserialization process. This method does not let it escape instead override with singlePresident and that deserialized instance is garbage collected in almost no time. Now how can an attacker misuse this deserialization step involved in the process.

An attacker will make use of serialized steam , create an Dummy class , will create an private instance referring to s3erialized instance of President class.

 Ok ok , lets get into that code ;

Public class Dummy {
Private static President impersonator;
Private President instance;

readResolve (){
instance=impersonator;
}

}   

What is happening here. Attacker used stream deserializing President instance  , injected an instance of Dummy class in that. Further  Dummy class has an instance of President class. So here we are having circularity. When deserialization will happen , instance of Dummy class being inside deserializing President class, readResolve() method of Dummy class will be invoked first.

As you see in above code . What does this method do in Dummy class. 

 This method is assigning deserializing instance to static impersonator variable. So even after deserialization is complete Dummy class have cleverly retained the instance of deserialized class in static field impersonator.

So actually happened here 

 two instances of President class are available , one by attacker  impersonator and one original singlePresident returned by readResolve() method of President class. So attacker could successfully break our instance control to single.



That’s the reason Effective java says For instance control, prefer enum types to readResolve as ENUM = perfect singleton implementation




Please comment for any question or to discuss it further





1 comment:

  1. Hi.. its great post full of original source of info . A most effective topic over here .
    Good to read will bookmark it for visit again.
    Keep up the good work !

    ReplyDelete