library
intermediateSerialization & Deserialization
Understand Java's built-in serialization, serialVersionUID, transient, and the security concerns.
Serialization turns an object graph into bytes. The class must implement Serializable.
Serialization = freeze-drying food (preserving state for transport). Deserialization = rehydrating it. But someone could tamper with the freeze-dried packet (untrusted data = security risk).
Key Concepts
1
class Order implements Serializable {
private static final long serialVersionUID = 1L;
private String id;
private transient String cardNumber; // excluded
}2
try (var out = new ObjectOutputStream(new FileOutputStream("o.ser"))) {
out.writeObject(order);
}3
Always declare serialVersionUID yourself. Leave it out and the compiler derives one from the class
structure — so adding a field changes it, and reading old data then throws InvalidClassException.
serialVersionUIDInvalidClassException
4
The rules.
transient fields skipped; come back as null / 0 / false
static fields never written -- they belong to the class
the whole graph every referenced object must also be
Serializable, or NotSerializableException5
Deserialization does not call your constructor. The JVM allocates the object and sets fields by
reflection, so every validation you wrote is bypassed:
6
Order(String id) {
if (id == null) throw new IllegalArgumentException(); // never runs
}7
Which is the root of the security problem. Deserialising untrusted bytes lets an attacker construct
arbitrary objects in your JVM, and chains of ordinary library classes have been used to reach remote code
execution.
8
// Java 9+: restrict what may be deserialised
ObjectInputFilter.Config.setSerialFilter(
ObjectInputFilter.Config.createFilter("com.shop.*;!*"));9
So do not use Java serialization for anything external. JSON or protobuf for data crossing a boundary;
Java serialization at most between processes you control, behind a filter.
10
The customisation hooks, for the cases where you must.
11
writeObject / readObject custom format for one class
writeReplace swap in another object when writing
readResolve swap in another after reading --
this is how a singleton stays single
Externalizable full manual control12
readResolve is the one to remember. Without it, deserialising a singleton creates a second instance and
quietly breaks the guarantee. An enum singleton has no such problem.
readResolve
13
What the interviewer is probing.1. "Why is Java serialization considered dangerous?" Probing: the security argument. Stalls:
"It is just old." Moves up: deserialisation constructs objects without calling constructors, so
validation is bypassed, and gadget chains in ordinary libraries have reached remote code execution.
14
2. "What does serialVersionUID do and why declare it?" Probing: versioning. Stalls: "It is a
version number." Moves up: it identifies the class version; omit it and the compiler derives one
from the structure, so adding a field makes old data unreadable with InvalidClassException.
15
3. "How do you preserve a singleton across deserialisation?" Probing: readResolve. Stalls:
"It just works." Moves up: implement readResolve to return the existing instance — otherwise
deserialising creates a second one. An enum singleton has no such problem.
16
4. "What should you use instead for data crossing a boundary?" Probing: whether you reach the
practical conclusion. Stalls: "Java serialization is fine internally." Moves up: JSON or
protobuf, with Java serialization at most between processes you control and behind an
ObjectInputFilter.