The problem is that the readObject method is effectively another public constructor, and it demands all of the same care as any other constructor. Just as a constructor must check its arguments for validity and make defensive copies of parameters where appropriate, so must a readObject method. If a readObject method fails to do either of these thing, it is a relatively simple matter for an attacker to violate the class's invariant.
Loosely speaking, readObject is a constructor that takes a byte stream as its solo parameter. In normal use, the byte stream is generated by serializing a normally constructed instance. The problem arises when readObject is presented with a byte stream that is artificially constructed to generate an object that voilates the invariant of its class.
private static Object deserialize(byte[] sf){
try{
InputStream is = new ByteArrayInputStream(sf);
ObjectInputStream ois = new ObjectInputStream(is);
return ois.readObject();
}catch(Exception e){
throw new IllegalArgumentException(e);
}
}
The byte array literal used to initialize serializedForm was generated by serializing a normal Period instance and hand-editing the resulting byte stream.
The serialization byte-stream format is described in the Java(TM) Object Serialization Specification.
While the Period instance is created with its invariants intact, it is possible to modify its internal components at will. Once is possession of a mutable Period instance, an attacker might cause great harm by passing the instance on to a class that depends on Period's immutability for its security. This is not so far-fetched: there are classes depend on String's immutability for their security.
When an object is deserialized, it's critical to defensively copy any field containing an object reference that a client must not possess.
Therefore, every serializable immutable class containing private mutable components must defensively copy these components in its readObject method.
A simple litmus test for decideing whether the default readObject method is acceptable for a class:
Would you feel comfortable adding a public constructor that took as parameters the values for each nontransient filed in the object and stored the values in the fields with no validation whatsoever?