Skip to main content

Serialization

Source: Effective Java, 3rd Edition — Chapter 12 by Joshua Bloch (Items 85–87)

Java serialization encodes object graphs as bytes — and opens a large attack surface (gadget chains, deserialization bombs). These items: avoid it when you can, implement Serializable only with care, and design a logical serialized form.

Item 85: Prefer alternatives to Java serialization​

Deserialization invokes readObject on types that implement Serializable — including library gadgets you never intended to run. Untrusted byte streams can mean RCE, DoS (deserialization bombs), or worse.

Winning move: don’t play — don’t deserialize untrusted data. For new systems use JSON, Protocol Buffers, or similar cross-platform structured data (attribute maps, not arbitrary object graphs).

If legacy serialization is unavoidable:

  • Never accept untrusted streams (including careless RMI)
  • Use ObjectInputFilter (Java 9+) — prefer whitelisting over blacklisting
  • Filters limit class/memory depth but won’t stop all bombs
Quiz

Alternatives to Java serialization

1 / 2

New microservice exchanging data with a browser and a Go backend

Pick an answer to see if you are right.

Item 86: Implement Serializable with great caution​

implements Serializable is a long-term API commitment: the serialized form becomes exported forever. Default serialization exposes private fields and ties you to the physical representation.

Costs:

  • Evolution — missing serialVersionUID breaks compatibility when the class changes
  • Security — deserialization is a hidden constructor (Item 88)
  • Testing — round-trip across releases

Declare explicitly:

private static final long serialVersionUID = 1L;

Inner classes should not implement Serializable (ill-defined default form). Static member classes may. Classes for inheritance rarely should implement Serializable.

Quiz

Implementing Serializable

1 / 2

Non-static inner class implements Serializable

Pick an answer to see if you are right.

Item 87: Consider using a custom serialized form​

Default serialized form mirrors the physical object graph — often wrong when representation ≠ logical state (linked lists, hash tables).

Prefer custom writeObject / readObject emitting logical data only. Mark implementation fields transient. Still call defaultWriteObject/defaultReadObject first (even if all fields are transient) for forward compatibility.

Document serialized fields with @serial and custom writers with @serialData. Declare serialVersionUID.

Items 85–87 map​

ItemMove
85JSON/protobuf; never deserialize untrusted bytes
86Serializable is a commitment; serialVersionUID; no inner classes
87Custom form = logical state; transient implementation fields

Next: Safe Deserialization (Items 88–90).