Working with Serialization
1. Implementing Serializable Interface
Example: Serializable
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private transient String password; // not serialized
}
| Aspect | Detail |
|---|---|
| Marker interface | No methods |
| Required field | serialVersionUID recommended |
| Excluded fields | transient and static |
2. Using ObjectOutputStream
| Method | Use |
|---|---|
writeObject(o) | Serialize object graph |
writeInt/Double/UTF | Primitive writes |
flush() / close() | Resource management |
3. Using ObjectInputStream
Example: Read object
try (ObjectInputStream in = new ObjectInputStream(Files.newInputStream(path))) {
User u = (User) in.readObject();
}
| Method | Use |
|---|---|
readObject() | Returns Object — cast required |
| Throws | ClassNotFoundException, InvalidClassException |
4. Understanding serialVersionUID
| Aspect | Detail |
|---|---|
| Purpose | Version identifier for class |
| Mismatch | Throws InvalidClassException |
| Auto-computed | Based on class structure (fragile) |
| Recommendation | Always declare explicitly |
5. Using transient Keyword
| Effect | Detail |
|---|---|
| Skip serialization | Field not written |
| On deserialization | Field gets default value (0/null/false) |
| Use for | Passwords, caches, computed fields |
6. Customizing Serialization
Example: Custom serialization
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
out.writeInt(computedValue);
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
this.computedValue = in.readInt();
}
private Object readResolve() { return Singleton.INSTANCE; }
| Hook | Use |
|---|---|
writeObject/readObject | Custom format |
readResolve | Replace deserialized object (singletons) |
writeReplace | Substitute before write |
7. Implementing Externalizable Interface
| Aspect | Detail |
|---|---|
| Methods | writeExternal/readExternal |
| Constructor | Must have public no-arg |
| Use case | Full control over format (rare) |
8. Understanding Serialization Security Concerns
| Risk | Detail |
|---|---|
| Deserialization attacks | Hostile streams can execute arbitrary code via gadget chains |
| Mitigation | Use ObjectInputFilter to whitelist classes |
| Modern alternative | JSON/Protobuf/Avro/CBOR |
Warning: Java serialization is widely considered legacy. Prefer JSON/Protobuf for new code.
9. Handling Versioning Issues
| Compatible Change | Incompatible Change |
|---|---|
| Add field (default value used) | Change field type |
| Add method | Remove field (with old data) |
| Make non-final | Move class to different package |
10. Using Serialization Proxy Pattern
| Step | Detail |
|---|---|
| 1. Inner proxy class | Holds simplified state |
2. writeReplace() | Returns proxy instead of self |
3. readResolve() | Reconstruct from proxy |
| 4. Block direct deserialization | readObject throws |