Java Serialization and Deserialization with Serializable
Understand Java serialization with a working byte-stream example, Serializable, transient fields, serialVersionUID, compatibility errors, and JSON alternatives.
Last reviewed: November 2026
🔍 What Is It?
Java serialization writes an object's state to a byte stream; deserialization reconstructs an object from that stream. For ordinary classes, implement Serializable and use ObjectOutputStream.writeObject and ObjectInputStream.readObject. This native Java format is different from JSON serialization with Jackson.
Java Built-in Serialization:
- →Implement
java.io.Serializable(marker interface) - →Use
ObjectOutputStreamto serialize,ObjectInputStreamto deserialize - →
serialVersionUID— version ID for compatibility checking - →
transient— exclude fields from serialization - →
readObject/writeObject— customize serialization behavior
What gets serialized:
- →All non-transient, non-static instance fields
- →Recursively: all referenced objects (must also be Serializable)
Externalizable:
- →More control: you implement readExternal/writeExternal
- →Owns the stream format and its versioning; performance depends on the implementation
- →Requires a public no-arg constructor
Modern Alternatives:
- →JSON (Jackson, Gson) — human-readable, language-neutral, widely supported
- →Protobuf — binary, fast, schema-based, language-neutral
- →Avro — schema-based, great for Kafka
- →Kryo — fast Java binary serialization (not language-neutral)
- →Records — immutable data classes, serialize well with Jackson
🎯 Why Do We Need It?
Serialization is needed for:
- →Persistence — save objects to disk (session state, caches)
- →Network transmission — send objects over the network (RMI, Kafka, Redis)
- →Caching — store objects in distributed caches (Redis, Hazelcast)
- →Deep copy — serialize and deserialize to create a deep copy
However, Java's built-in serialization has serious problems: security vulnerabilities (deserialization attacks), tight coupling to class structure, poor performance. Use JSON or Protobuf instead.
🏗️ What Happens in Real Projects?
In enterprise Java:
- →REST APIs — Jackson for JSON serialization/deserialization
- →Kafka — Avro or JSON for message serialization
- →Redis cache — JSON serialization via Spring Data Redis
- →HTTP sessions — built-in serialization (if distributed session storage)
- →JPA — not serialization; JPA maps objects to SQL directly
⚙️ How It Works
Built-in serialization process:
- ObjectOutputStream writes class descriptor (class name, serialVersionUID, field names/types)
- Writes field values recursively
- On deserialization: checks class compatibility and reconstructs the object. For ordinary Serializable classes, their constructors are skipped, but the first non-serializable superclass's accessible no-arg constructor runs. Externalizable classes and serializable records have different construction rules.
serialVersionUID:
If not declared, Java computes a UID from class details. Structural changes can change that value and prevent old streams from being read. Declare a stable UID for compatible evolution, then evaluate the actual change: adding a field can be compatible, while changing a field's type can be incompatible even with the same UID. Matching UIDs alone do not make every schema change safe.
Security issue:
Deserializing untrusted data can execute arbitrary code (gadget chains). Never deserialize data from untrusted sources with Java built-in serialization.
💻 Example
Serialization Patterns — When to use built-in serialization and modern alternatives.
🤔 Common Confusions
❓ Should I use Java built-in serialization or JSON?
Choose a format based on the system contract. JSON is widely used for REST APIs and cross-language messages; native Java serialization is mainly relevant to existing Java-only protocols or frameworks that require it. Neither format is automatically safe: validate data and avoid unsafe polymorphic deserialization. Benchmark performance for your actual payloads.
❓ What happens if I change a Serializable class?
An automatically computed serialVersionUID can change with class details, causing old streams to be rejected. Declare a stable UID for compatible changes and test old data. New fields absent from an old stream receive default values, not values from field initializers. Matching UIDs do not make incompatible field-type changes safe.
🚨 Common Production Issues
Deserialization of untrusted data — Java built-in deserialization can execute arbitrary code via gadget chains. Never deserialize untrusted data. Use ObjectInputFilter (Java 9+) to whitelist allowed classes.
serialVersionUID mismatch — a changed computed UID or an intentionally changed explicit UID can break old cached data. Keep the UID stable for compatible changes and plan migrations for incompatible changes.
Non-serializable fields causing NotSerializableException — all referenced objects must also be Serializable, or marked transient.
✅ Best Practices
Use Jackson/JSON instead of built-in serialization for new code.
Always declare serialVersionUID explicitly in Serializable classes.
Mark non-serializable fields as transient.
Never deserialize data from untrusted sources with built-in serialization.
Use @JsonIgnoreProperties(ignoreUnknown=true) for forward compatibility.
Configure ObjectMapper before use, then reuse it; avoid changing shared configuration after reads or writes begin.
🏛️ Architect's Note
Choose serialization formats as part of the service contract. JSON is widely supported and easy to inspect. Protobuf or Avro can provide compact messages and explicit schemas, but compare compatibility rules and benchmark representative payloads. For Kafka, Avro with a schema registry is one common option; choose according to the consumers and evolution requirements.
💬 Frequently Asked Questions
🎯 Key Takeaways
🔗 Related Topics
🎯 Practice this topic in interviews
Core Java Interview Prep
Practice interview questions that connect directly to this technology track.
↗ Where this topic fits
Core Java Technology Guide
Return to the Core Java learning hub.
Backend Engineer Career Path
A structured journey through Core Java, Spring Boot, production backend engineering, and interview preparation.
Full Stack Java Developer Career Path
A guided route through frontend foundations, Java backend engineering, delivery workflows, and interview readiness.
Sources
Sources / References
Use these Core Java references to verify the concept in official docs and continue into the most relevant SplashRide pages.
Official documentation
Related SplashRide pages
SplashRide Core Java learning path
Browse the full Core Java topic collection and learning order on SplashRide.
Core Java Interview Prep
Practice Core Java interview questions and scenario-based answers.
Backend Engineer Career Path
A structured journey through Core Java, Spring Boot, production backend engineering, and interview preparation.
Full Stack Java Developer Career Path
A guided route through frontend foundations, Java backend engineering, delivery workflows, and interview readiness.
Classes & Objects
The foundation of Java OOP — how classes define blueprints and objects are instances, with constructors, fields, methods, and the this keyword.
Generics
Java Generics — type parameters, bounded wildcards, type erasure, and how generics make collections and APIs type-safe.