Object Oriented Programming in JavaUnit 1510 min read
Serialization in Java: Objects to Bytes & Back
Unit 15 of Object Oriented Programming in Java covers serialization—how to convert Java objects into byte streams for storage/transmission and reconstruct them, including transient fields, versioning, and security risks. Learn syntax, use cases, and pitfalls with real-world examples from eSewa and banking systems.
TAKEAWAYS:
- Serialization converts objects into byte streams using
SerializableandObjectOutputStream/ObjectInputStream. - Transient fields are excluded from serialization; static fields are ignored.
- Versioning via
serialVersionUIDensures compatibility across updates. - Security risks include malicious object deserialization (e.g., attacks via crafted byte streams).
- Used in distributed systems (e.g., RMI, Hibernate) and persistence (saving game states, user profiles).
1. What is Serialization?
Serialization is the process of converting an object’s state into a byte stream to store it or transmit it over a network. When needed, the byte stream is deserialized back into an object.
Why Use Serialization?
- Persistence: Save object state to files/databases (e.g., user profiles in eSewa).
- Network Transmission: Send objects between systems (e.g., Daraz order processing).
- Distributed Computing: Share objects in RMI or Spring frameworks.
Key Interfaces/Classes
| Interface/Class | Purpose |
|---|---|
Serializable |
Marker interface (no methods); marks a class as serializable. |
ObjectOutputStream |
Writes objects to a stream (e.g., file/network). |
ObjectInputStream |
Reads objects from a stream. |
Externalizable |
Custom serialization logic (rarely used). |
2. How Serialization Works
Step-by-Step Process
- Mark the class as
Serializable:class User implements Serializable { private String name; private transient String password; // Not serialized private static int count; // Ignored } - Serialize to a file:
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("user.dat"))) { User user = new User("Alice", "pass123"); oos.writeObject(user); // Converts User to bytes } - Deserialize from the file:
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("user.dat"))) { User loadedUser = (User) ois.readObject(); // Reconstructs User }
Visual: Serialization Flow
flowchart TD
A["Object (User)"]
B["ObjectOutputStream"]
C["Byte Stream (user.dat)"]
D["ObjectInputStream"]
E["Reconstructed Object"]
A -->|"writeObject()"| B -->|"File"| C -->|"readObject()"| D --> EWhat Gets Serialized?
- Included: Instance variables (non-static, non-transient).
- Excluded:
- Static fields (belong to the class, not objects).
- Transient fields (marked with
transient). - Non-serializable parent classes (unless they implement
Serializable).
3. Real-World Examples
In the Real World
eSewa (Nepal):
- Uses serialization to save user transaction history (e.g., electricity bill payments) in a portable format for backup/recovery.
- How: Objects like
TransactionRecordimplementSerializableand are stored in encrypted byte streams.
Khalti (Digital Wallet):
- Serializes payment request objects when sending them to banks for processing.
- How: A
PaymentRequestobject is converted to bytes, transmitted securely, and deserialized by the bank’s system.
Nepal Rastra Bank’s Loan Systems:
- Serializes loan applicant data (e.g.,
LoanApplication) to disk for auditing. - Why: Ensures data integrity even if the system crashes.
- Serializes loan applicant data (e.g.,
4. Versioning and Compatibility
Problem: Class Changes Over Time
If you modify a class (e.g., add/remove fields), deserialization may fail. Solution: serialVersionUID.
Example: Adding a Field
class User implements Serializable {
private static final long serialVersionUID = 1L; // Explicit UID
private String name;
private String email; // Added later
}
- Without
serialVersionUID: Java generates a default UID. If the class changes, the UID changes → deserialization fails. - With
serialVersionUID: Ensures backward compatibility.
Visual: Versioning Impact
flowchart TD
A["Class V1\n(serialVersionUID=1)"] -->|"Adds 'email' field"| B["Class V2\n(serialVersionUID=1)"]
B -->|"Deserialize old data"| C["Works if UID matches"]
B -->|"Deserialize old data (UID mismatch)"| D["Error: InvalidClassException"]5. Security Risks: Deserialization Attacks
Malicious byte streams can exploit vulnerabilities in deserialization. Example:
- Gadget Chains: Attackers craft byte streams that execute arbitrary code during deserialization.
- Real-World Impact: Used in ransomware (e.g., Java-based attacks on corporate systems).
Mitigation Strategies
- Validate Input: Never deserialize untrusted data.
- Use
ObjectInputFilter(Java 9+):ObjectInputFilter filter = ObjectInputFilter.Config.createFilter("!com.evil.*"); ois.setObjectInputFilter(filter); - Avoid Serialization for Sensitive Data: Use encryption instead.
6. Worked Example: Saving a Bank Account
Scenario
A bank saves Account objects to a file for daily backups. The Account class has:
accountNumber(serialized)balance(serialized)password(transient, not saved)
Code Implementation
import java.io.*;
class Account implements Serializable {
private String accountNumber;
private transient String password; // Not saved
private double balance;
public Account(String accNum, String pwd, double bal) {
this.accountNumber = accNum;
this.password = pwd;
this.balance = bal;
}
}
public class BankBackup {
public static void main(String[] args) {
Account account = new Account("12345", "secret", 1000.0);
// Serialize
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("account.dat"))) {
oos.writeObject(account);
System.out.println("Account saved!");
} catch (IOException e) {
e.printStackTrace();
}
// Deserialize
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("account.dat"))) {
Account loadedAccount = (Account) ois.readObject();
System.out.println("Account Number: " + loadedAccount.accountNumber);
System.out.println("Balance: " + loadedAccount.balance);
// Password is null (transient)
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
Trace Table: Serialization Steps
| Step | Action | State After Step |
|---|---|---|
| 1 | Create Account object |
accountNumber="12345", balance=1000 |
| 2 | Call oos.writeObject(account) |
Byte stream written to account.dat |
| 3 | Read from account.dat |
loadedAccount.accountNumber="12345" |
| 4 | Access password |
null (transient field) |
7. Custom Serialization with writeObject/readObject
For full control, override:
private void writeObject(ObjectOutputStream oos) throws IOException {
oos.writeUTF(accountNumber);
oos.writeDouble(balance);
// Skip password
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
accountNumber = ois.readUTF();
balance = ois.readDouble();
password = "default"; // Set default
}
8. Comparison: Serialization vs. Alternatives
| Feature | Serialization | JSON/XML | Database Storage |
|---|---|---|---|
| Complexity | High (tied to Java) | Low (human-readable) | Medium (SQL/NoSQL queries) |
| Performance | Fast for Java objects | Slower (parsing overhead) | Fast (optimized for storage) |
| Portability | Java-only | Cross-language | Database-specific |
| Security | Vulnerable to attacks | Safe if validated | Safe (with proper access) |
| Use Case | Internal Java systems | APIs, configs | Large-scale data storage |
9. Common Pitfalls
- Forgetting
Serializable:// Throws NotSerializableException oos.writeObject(new NonSerializableClass()); - Transient Fields:
- Always mark sensitive fields (e.g., passwords) as
transient.
- Always mark sensitive fields (e.g., passwords) as
- Circular References:
- Objects referencing each other can cause infinite loops. Use
ObjectOutputStream.putFields()to handle this.
- Objects referencing each other can cause infinite loops. Use
- Version Mismatch:
- Always define
serialVersionUIDfor long-lived classes.
- Always define
Exam Tip
Key Questions:
- Explain how to serialize an object to a file (4 marks).
- Differentiate
transientandstaticin serialization (2 marks). - Write a program to save/load an object (6 marks).
- Discuss security risks of deserialization (3 marks).
Common Mistakes to Avoid:
- Forgetting to close streams (
try-with-resourcesis your friend). - Not handling
ClassNotFoundExceptionorIOException. - Assuming all fields are serialized (check for
transient/static).
- Forgetting to close streams (
Quick Code Template:
// Serialize try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("file.dat"))) { oos.writeObject(object); } // Deserialize try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("file.dat"))) { Object obj = ois.readObject(); }
10. Practice Questions
Short Answer:
- Why is
serialVersionUIDimportant? - What happens if a parent class is not
Serializable?
- Why is
Programming:
- Write a program to serialize a
Studentclass withname(serialized) androllNo(transient). Deserialize and print thename.
- Write a program to serialize a
Scenario-Based:
- A bank wants to save
LoanApplicationobjects. TheLoanApplicationhasapplicantName,loanAmount, andssn(transient). Write the serialization code and explain whyssnis markedtransient.
- A bank wants to save
Visual Summary: Serialization Process
sequenceDiagram
participant Object as User Object
participant OOS as ObjectOutputStream
participant File as user.dat
participant OIS as ObjectInputStream
participant Reconstructed as User Object
Object->>OOS: writeObject()
OOS->>File: Writes bytes
File-->>OIS: Reads bytes
OIS->>Reconstructed: readObject()Based on the TU BCA syllabus for Object Oriented Programming in Java (CACS204), unit 15.
Discussion
Loading…