Sunday, April 19, 2015

Effective Java (Remarked) - Serialization

Item 74: Implement Serializable judiciously (design, portability, performance, scalability)

A major cost of implementing Serializable is that it decreases the flexi- bility to change a class’s implementation once it has been released. A second cost of implementing Serializable is that it increases the likeli- hood of bugs and security holes. A third cost of implementing Serializable is that it increases the testing burden associated with releasing a new version of a class. Implementing the Serializable interface is not a decision to be under- taken lightly. Classes designed for inheritance should rarely implement Serializable, and interfaces should rarely extend it. Inner classes (Item 22) should not implement Serializable. To summarize, the ease of implementing Serializable is specious. Unless a class is to be thrown away after a short period of use, implementing Serializ- able is a serious commitment that should be made with care. Extra caution is war- ranted if a class is designed for inheritance. For such classes, an intermediate design point between implementing Serializable and prohibiting it in sub- classes is to provide an accessible parameterless constructor. This design point permits, but does not require, subclasses to implement Serializable.

When use? always.

Item 75: Consider using a custom serialized form (design, portability, performance, scalability)

Do not accept the default serialized form without first considering whether it is appropriate. The default serialized form is likely to be appropriate if an object’s phys- ical representation is identical to its logical content. Even if you decide that the default serialized form is appropriate, you often must provide a readObject method to ensure invariants and security. To summarize, when you have decided that a class should be serializable (Item 74), think hard about what the serialized form should be. Use the default serialized form only if it is a reasonable description of the logical state of the object; otherwise design a custom serialized form that aptly describes the object.

When use? always.

Item 76: Write readObject methods defensively (design, portability, performance, scalability)

When an object is deserialized, it is critical to defensively copy any field containing an object reference that a client must not possess. To summarize, anytime you write a readObject method, adopt the mind-set that you are writing a public constructor that must produce a valid instance regard- less of what byte stream it is given. Do not assume that the byte stream represents an actual serialized instance. 

When use? always.

Item 77: For instance control, prefer enum types to readResolve (design, portability, performance, scalability)

To summarize, you should use enum types to enforce instance control invariants wherever possible. If this is not possible and you need a class to be both serializable and instance-controlled, you must provide a readResolve method and ensure that all of the class’s instance fields are either primitive or transient.

When use? always.

Item 78: Consider serialization proxies in stead of serialized instances (design, portability, performance, scalability)

In summary, consider the serialization proxy pattern whenever you find your- self having to write a readObject or writeObject method on a class that is not extendable by its clients. This pattern is perhaps the easiest way to robustly serialize objects with nontrivial invariants.


When use? always.

No comments: