Definition
Serialization basics:
- **Serialize:** Object → byte stream (ObjectOutputStream.writeObject). - **Deserialize:** Byte stream → Object (ObjectInputStream.readObject). - **Serializable:** Marker interface. Without it, serialization throws NotSerializableException. - **What is serialized:** All non-static, non-transient instance fields. - **Constructor NOT called:** Deserialization bypasses the constructor entirely.
Serialization is like converting a bank account record into a barcode for shipping. Deserialization scans the barcode and reconstructs the record at the destination. The Serializable stamp on the account class says "this record is eligible for barcode conversion."
Understanding the Concepts
How does serialization work?
import java.io.*;
public class Account implements Serializable {
private static final long serialVersionUID = 1L;
private String accountId;
private BigDecimal balance;
private transient String password; // NOT serialized
private static int count = 0; // NOT serialized (static)
}
// Serialize
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("account.ser"))) {
oos.writeObject(new Account("SAV2001", new BigDecimal("500000")));
}
// Deserialize
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("account.ser"))) {
Account a = (Account) ois.readObject();
System.out.println(a.getAccountId()); // SAV2001
System.out.println(a.getBalance()); // 500000
System.out.println(a.getPassword()); // null (transient)
}
What is NOT serialized?
- static fields: Belong to the class, not the object.
- transient fields: Explicitly excluded. Reset to default (0, null, false) on deserialization.
Why is Java serialization discouraged in new code?
- Security risk: Deserializing untrusted data can execute arbitrary code (deserialization attacks).
- Brittle: Adding/removing fields breaks compatibility without careful versioning.
- Not human-readable: Binary format, hard to debug.
- Modern alternatives: JSON (Jackson), Protobuf, Avro are safer, cross-language, and easier to evolve.
What should a senior engineer know?
- serialVersionUID ensures version compatibility. Without it, the JVM generates one from class structure, and any change breaks deserialization.
- readObject/writeObject methods customize serialization behavior.
- Java 17+ deserialization filters (
ObjectInputFilter) restrict which classes can be deserialized. - Spring uses JSON/HTTP for REST APIs, not Java serialization. JPA handles object-relational mapping, not serialization.
What are common mistakes?
A common mistake is forgetting to declare serialVersionUID, which causes deserialization failures when the class changes.
Wrong approach:
package com.bank.model;
import java.io.Serializable;
// WRONG: no serialVersionUID
public class Account implements Serializable {
private String accountId;
private java.math.BigDecimal balance;
}
// If you add a field later, old serialized data cannot be read
Correct approach:
package com.bank.model;
import java.io.Serializable;
import java.math.BigDecimal;
// CORRECT: explicit serialVersionUID
public class Account implements Serializable {
private static final long serialVersionUID = 1L;
private String accountId;
private BigDecimal balance;
}
// Adding new fields with defaults still allows reading old data
Another mistake is serializing sensitive fields like passwords or PINs. Always mark them transient to exclude them from the byte stream.
What are the edge cases?
Edge cases can cause unexpected behavior in banking applications. Here are some to watch for.
package com.bank.edge;
public class EdgeCaseDemo {
public static void main(String[] args) {
// Edge case 1: null handling
String accountId = null;
try {
System.out.println(accountId.length());
} catch (NullPointerException e) {
System.out.println("Null account ID");
}
// Edge case 2: empty vs null
String emptyId = "";
System.out.println(emptyId.isEmpty()); // true
System.out.println(emptyId == null); // false
// Edge case 3: boundary values
java.math.BigDecimal zero = java.math.BigDecimal.ZERO;
java.math.BigDecimal negativeBalance = new java.math.BigDecimal("-0.01");
System.out.println(zero.compareTo(negativeBalance) > 0); // true
}
}
Null account ID
true
false
true
Always test with null values, empty strings, boundary values, and negative amounts in banking applications.
What are common interview follow-up questions?
Interviewers often follow up with these related questions:
- How does this concept apply to a high-throughput banking transaction system?
- What are the performance implications in a production environment?
- How would you debug issues related to this concept?
- What tools would you use to monitor this in production?
- How does this behave differently in Java 8 vs Java 17+?
When answering follow-up questions, always relate your answer back to practical experience. For example, at National Bank of India, Rajesh debugged a production issue related to this concept by using JFR recordings and heap dumps. Providing concrete examples from banking systems shows the interviewer that you understand both the theory and the practice.
Visual Overview
Object → ObjectOutputStream.writeObject() → byte[] → file/network byte[] → ObjectInputStream.readObject() → Object (constructor NOT called) Serialized: non-static, non-transient instance fields NOT serialized: static fields, transient fields Required: implements Serializable Modern: prefer JSON (Jackson) or Protobuf over Java serialization
Key Takeaway
Serialization converts an object to a byte stream for storage or network transmission. The class must implement Serializable. Static and transient fields are excluded. The constructor is not called during deserialization.
In modern Java, avoid Java serialization for new code. Use JSON (Jackson), Protobuf, or Avro instead. They are safer, cross-language, and easier to evolve.
One sentence to remember: serialization converts objects to bytes, requires Serializable, skips static and transient fields, and is replaced by JSON in modern code.
---