When implementing the Serializable interface and implementing the readObject method it is important to remember that it is effectively a public constuctor and so similarly arguments must be checked for validity and defensive copies of parameters must be made where necessary.
Serializable interface documentation
The readObject method is responsible for reading from the stream and restoring the classes fields. It may call in.defaultReadObject to invoke the default mechanism for restoring the object’s non-static and non-transient fields. The defaultReadObject method uses information in the stream to assign the fields of the object saved in the stream with the correspondingly named fields in the current object. This handles the case when the class has evolved to add new fields. The method does not need to concern itself with the state belonging to its superclasses or subclasses. State is saved by writing the individual fields to the ObjectOutputStream using the writeObject method or by using the methods for primitive data types supported by DataOutput.
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException;
To ensure that your readObject method is bulletproof, follow the following rules, as recommended by Bloch, when it comes to any particular class:
- Defensively copy each object referenced by object reference fields that are private. This also applies to the mutable objects of immutable classes.
- Check all invariants, that would predominantly also be checked in public constructors, and throw an InvalidObjectException if a check fails. The check should come after any defensive copying.
- It may be that an entire object graph must be validated after it is deserialized, in such cases use the ObjectInputValidation interface.
- Be sure to not invoke any overridable methods in the class, directly or indirectly.
- Effective Java, Second Edition, Joshua Bloch, Item 76: Write readObject methods defensively
- Java Practices -> Implementing Serializable