Serialization: Serializable, transient and safer alternatives
Serialization turns an object into bytes (to save to a file or send over a network); deserialization turns the bytes back into an object.
- A class opts in by implementing the marker interface Serializable.
- ObjectOutputStream.writeObject() writes the object and everything it references; ObjectInputStream.readObject() rebuilds it.
- transient fields are skipped (passwords, caches, connections) and come back as default values. static fields aren't serialized either.
- serialVersionUID identifies the class version. If the stored ID doesn't match the class, deserialization fails with InvalidClassException, so declare it explicitly.
- The class's own constructors don't run during deserialization.
Java serialization is now considered risky and legacy: deserializing untrusted bytes can run attacker-controlled code ("gadget chains"). For new code prefer JSON (Jackson), Protocol Buffers or another explicit format. If you must use it, install a deserialization filter (ObjectInputFilter).
Example
record Address(String city, String pin) implements Serializable {}
class User implements Serializable {
@Serial private static final long serialVersionUID = 1L; // @Serial: Java 14+
private final String email;
private final Address address; // must be Serializable too
private transient String sessionToken; // never written
User(String email, Address address, String token) {
this.email = email; this.address = address; this.sessionToken = token;
}
}
User asha = new User("asha@example.com", new Address("Pune", "411001"), "secret-123");
try (var out = new ObjectOutputStream(new FileOutputStream("user.bin"))) {
out.writeObject(asha);
}
try (var in = new ObjectInputStream(new FileInputStream("user.bin"))) {
in.setObjectInputFilter(ObjectInputFilter.Config.createFilter("com.shop.*;java.base/*;!*")); // allow-list
User copy = (User) in.readObject(); // sessionToken is null in the copy
}Common mistake
Deserializing data from users, files or the network with a plain ObjectInputStream. That has been the root cause of many remote-code-execution vulnerabilities.
Under the hood
Records serialize more safely than ordinary classes: deserialization goes through the canonical constructor, so its validation runs. Externalizable gives full manual control. In distributed systems, a stable, versioned schema (JSON with explicit fields, Avro, Protobuf) avoids the tight coupling of Java serialization, where renaming a private field can break stored data.
Check yourself
Which field is NOT written by ObjectOutputStream?
How this connects
Know these first
Where this leads
You've reached the end of this thread. Try a learning path for what's next.
Was this lesson helpful?
Finished reading? Mark it complete to track your progress.