Java serialization turns an object graph into bytes (and back) — built into the language, but now considered a legacy mechanism with real security risks.
A round trip in memory
import java.io.*;
public class Main {
static class User implements Serializable {
private static final long serialVersionUID = 1L;
String name;
int age;
transient String password; // not written
static String company = "Acme"; // static: belongs to the class, not written
User(String name, int age, String password) {
this.name = name; this.age = age; this.password = password;
}
}
public static void main(String[] args) throws Exception {
User original = new User("Asha", 30, "s3cret");
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
try (ObjectOutputStream out = new ObjectOutputStream(bytes)) {
out.writeObject(original);
}
User copy;
try (ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes.toByteArray()))) {
copy = (User) in.readObject();
}
System.out.println(copy.name + " " + copy.age + " " + copy.password);
System.out.println(copy == original);
}
}Asha 30 null
falseThe rules
| Rule | Detail |
|---|---|
implements Serializable | marker interface — no methods. Otherwise NotSerializableException. |
| Every field must be serializable | or transient/static. One non-serializable field fails the whole graph. |
transient | skip this field (passwords, caches, Threads, connections). |
static fields | never serialized — they belong to the class. |
| Superclass | if the parent isn't Serializable, it needs an accessible no-arg constructor, which runs on deserialization. |
| Object graph | references are followed; shared objects and cycles are written once. |
| Custom format | private void writeObject(ObjectOutputStream) / readObject(ObjectInputStream), or Externalizable. |
import java.io.*;
public class Main {
static class Connection {} // NOT Serializable
static class Session implements Serializable {
private static final long serialVersionUID = 1L;
String user = "asha";
Connection conn = new Connection(); // fix: mark it transient
}
public static void main(String[] args) throws IOException {
try (ObjectOutputStream out = new ObjectOutputStream(new ByteArrayOutputStream())) {
out.writeObject(new Session());
} catch (NotSerializableException e) {
System.out.println("NotSerializableException: " + e.getMessage());
}
}
}NotSerializableException: Main$ConnectionserialVersionUID
A version number stored in the stream. On deserialization, the JVM compares it with the current class; if they differ you get InvalidClassException. If you don't declare one, the compiler computes it from the class's structure — so adding a method can break compatibility with previously saved data.
import java.io.Serializable;
class Order implements Serializable {
private static final long serialVersionUID = 1L; // declare it explicitly
private final String id;
private final int qty;
Order(String id, int qty) { this.id = id; this.qty = qty; }
String id() { return id; }
int qty() { return qty; }
}Security and modern alternatives
What is the purpose of serialVersionUID?
What does transient do? Are static fields serialized?
Serializable vs Externalizable?
Why is Java serialization considered dangerous?