Back to Serialization & transient
Q4Question 4 of 11

What is serialization and why must a class implement Serializable?

Key Concepts
  • Serialization converts an object's state to a byte stream for storage or network transmission
  • Deserialization reconstructs the object from the byte stream
  • The class must implement Serializable (marker interface) or ObjectOutputStream throws NotSerializableException
  • Serialization writes all non-static, non-transient fields
  • The constructor is NOT called during deserialization – the object is reconstructed from bytes
  • Modern alternatives: JSON (Jackson/Gson), Protobuf, Avro – avoid Java serialization in new code

Definition

Serialization converts an object to bytes for storage/network. The class must implement Serializable. Modern code prefers JSON or Protobuf over Java's built-in serialization.

Serialization basics:

DIAGRAM
- **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?

JAVA
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:

JAVA
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:

JAVA
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.

JAVA
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
    }
}
TEXT
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

DIAGRAM
  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.

---

Share
Use ← → arrow keys to navigate