Item 57: Provide a readResolve method when necessaryItem 2 describes the Singleton pattern and gives the following example of a singleton class. This class restricts access to its constructor to ensure that only a single instance is ever created:
As noted in Item 2, this class would no longer be a singleton if the words "implements Serializable" were added to its declaration. It doesn't matter whether the class uses the default serialized form or a custom serialized form (Item 55), nor does it matter whether the class provides an explicit readObject method (Item 56). Any readObject method, whether explicit or default, returns a newly created instance, which will not be the same instance that was created at class initialization time. Prior to the 1.2 release, it was impossible to write a serializable singleton class. In the 1.2 release, the readResolve feature was added to the serialization facility [Serialization, 3.6]. If the class of an object being deserialized defines a readResolve method with the proper declaration, this method is invoked on the newly created object after it is deserialized. The object reference returned by this method is then returned in lieu of the newly created object. In most uses of this feature, no reference to the newly created object is retained; the object is effectively stillborn, immediately becoming eligible for garbage collection. If the Elvis class is made to implement Serializable, the following readResolve method suffices to guarantee the singleton property:
This method ignores the deserialized object, simply returning the distinguished Elvis instance created when the class was initialized. Therefore the serialized form of an Elvis instance need not contain any real data; all instance fields should be marked transient. This applies not only to Elvis, but to all singletons. A readResolve method is necessary not only for singletons, but for all other instance-controlled classes, in other words, for all classes that strictly control instance creation to maintain some invariant. Another example of an instance-controlled class is a typesafe enum (Item 21), whose readResolve method must return the canonical instance representing the specified enumeration constant. As a rule of thumb, if you are writing a serializable class that contains no public or protected constructors, consider whether it requires a readResolve method. A second use for the readResolve method is as a conservative alternative to the defensive readObject method recommended in Item 56.� The beauty of this approach is that it virtually eliminates the extralinguistic component of serialization, making it impossible to violate any class invariants that were present before the class was made serializable. To make this technique concrete, the following readResolve method can be used in lieu of the defensive readObject method in the Period example in Item 56:
This readResolve method stops both of the attacks described Item 56 dead in their tracks. The defensive readResolve idiom has several advantages over a defensive readObject. It is a mechanical technique for making a class serializable without putting its invariants at risk. It requires little code and little thought, and it is guaranteed to work. Finally, it eliminates the artificial restrictions that serialization places on the use of final fields. While the defensive readResolve idiom is not widely used, it merits serious consideration.� The accessibility of the readResolve method is significant.� The previous paragraph hints at the reason the readResolve method may not be substituted for a defensive readObject method in classes that permit inheritance. If the superclass's readResolve method were final, it would prevent subclass instances from being properly deserialized. If it were overridable, a malicious subclass could override it with a method returning a compromised instance. To summarize, you must use a readResolve method to protect the "instance-control invariants" of singletons and other instance-controlled classes. In essence, the readResolve method turns the readObject method from a de facto public constructor into a de facto public static factory. The readResolve method is also useful as a simple alternative to a defensive readObject method for classes that prohibit inheritance outside their package.
|
Tuesday, October 27, 2009
Item 57: Provide a readResolve method when necessary
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment