Consider serialization proxies instead of serialized instances

The serialization proxy pattern is reasonably straightforward. First design a private static nested class of the serializable class. This nested class, known as the serialization proxy, should have a single constructor, whose parameter type is the enclosing class. This constructor merely copies the data from its argument: it need not do any consistency checking or defensive copying. By design, the default serialized form of the serialization proxy is the perfect serialized form of the enclosing class. Both the enclosing class and its serialization proxy must be declared to implement Serialible.

private Object writeReplace(){
    return new SerializationProxy(this);
}


The presence of this method causes the serialization system to emit a SerilizationProxy instance instead of an instance of the enclosing class. In other words, the writeReplace method translates an instance of the enclosing class to its serialization proxy prior to serialization.

With the writeReplace method in place, the serialization system will never generate a serialized instance of the enclosing class, but an attacker might fabricate one in an attempt to violate the class's invariants. To guarantee that such an attack would fail, merely add this readObject method to the enclosing class:

private void readObject(ObjectInputStream stream) throws InvalidObjectException{
    throw new InvalidObjectException("Proxy required");
}


Finally, provide a readResolve method on the SerializationProxy class that returns a logically equivalent instance of the enclosing class. The presence of this method causes the serialization system to translate the serialization proxy back into an enclosing class upon deserialization.

This readResolve method creates an instance of the enclosing class using only its public API, and therein lies the beauty of the pattern. It largely eliminates the extralinguistic character of serialization, because the deserialized instance is created using the same constructors, static factories, and methods as any other instance. This fees you from having to separately ensure that deserialized instances obey the class's invariants. If the class's static factories or constructors establish these invariants, and its instance methods maintain them, you've ensured that the invariants will be maintained by serializaiton as well.

Here is the readResolve method for Period.SerializationProxy above:
private Object readResolve(){
    return new Period(start,end);
}


In summary, consider the serialization proxy pattern whenever you find yourself 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.

你可能感兴趣的:(serialization)