I was asked this question in an interview. The interviewer wanted to know how to make an object immutable. and then he asked what if I serialise this object - will it break immu
You should read Effective Java written by Joshua Bloch. There is whole chapter about security issues connected with serialization and advices how to design your class properly.
In few words: you should learn about readObject and readResolve methods.
More detailed answer: Yes serialization can break immutability.
Let's assume you have class Period (it's example from Joshua's book):
private final class Period implements Serializable {
private final Date start;
private final Date end;
public Period(Date start, Date end){
this.start = new Date(start.getTime());
this.end = new Date(end.getTime());
if(this.start.compareTo(this.end() > 0)
throw new IllegalArgumentException("sth");
}
//getters and others methods ommited
}
It looks great. It's immutable (you can't change start and end after initialization), elegant, small, threadsafe etc.
But...
You have to remember that serialization is another way of creating objects (and it is not using constructors). Objects are build from byte stream.
Consider scenario when someone (attacker) change your serialization byte array. If he does such thing he could break your condition about start < end. Moreover there is possibility that attacker will put in stream (passed to deserialization method) reference to his Date object (which is mutable and Period class immutability will be completely destructed).
The best defense is not using serialization if you don't have to. If you have to serialize your class use Serialization Proxy pattern.
Edit (at kurzbot request): If you want to use Serialization Proxy you have to add static inner class inside Period. This class objects will be used for serialization instead of Period class objects.
In Period class write two new methods:
private Object writeReplace(){
return new SerializationProxy(this);
}
private void readObject(ObjectInputStream stream) throws InvalidObjectException {
throw new InvalidObjectException("Need proxy");
}
First method replace default serialized Period object with SerializationProxy object. Second guarantee that attacker won't use standard readObject method.
You should write writeObject method for SerializationProxy so you can use:
private Object readResolve() {
return new Period(start, end);
}
In that case you are using only public API and have certainty that Period class will remain immutably.