Java Object Serialization: Turning
Objects into Streams
A fundamental mechanism for persisting and transmitting object state in Java applications
What is Object Serialization?
Byte Stream Conversion Persistence
Transforms an object's state into a sequence of bytes that Saves objects to files or databases for later retrieval and use
can be stored or transmitted
Transmission Deserialization
Sends objects across networks between different Java Reconstructs the original object from the byte stream with
applications complete state
Why Use Serialization?
Lightweight Persistence
Save application state to files without complex database configurations
or external dependencies
Inter-Process Communication
Send objects between Java applications seamlessly using sockets, RMI,
or other network protocols
Caching Mechanism
Store frequently accessed objects for rapid retrieval, improving
application performance significantly
Deep Copying
Create completely independent copies of objects with all nested
references properly duplicated
The Core Mechanism
Object Output Stream and Object Input Stream
Object Output Stream Object Input Stream
Writes primitive data types and complex graphs of Java objects Reads primitive data types and object graphs from an
to an Output Stream. Handles the entire object graph InputStream. Reconstructs objects in the same structure they
automatically, including all referenced objects. were written, maintaining relationships.
Important: Objects must implement the [Link] interface to be serializable. This marker interface signals to
the JVM that the class can be safely converted to a byte stream.
Making Objects Serializable
serialVersionUID
Externalizable A unique identifier for class versions.
Serializable Interface Interface
Essential for maintaining
A marker interface that enables Provides custom control over compatibility between different
default serialization. Simply serialization. Requires implementing versions during deserialization and
implementing it allows the JVM to writeExternal() and readExternal() preventing InvalidClassException.
automatically serialize all non- methods for precise control.
transient fields.
How it Works: Writing an Object
ObjectOutputStream oos =
new ObjectOutputStream(
new FileOutputStream(
"[Link]"
)
);
[Link](myObject);
[Link]();
The writeObject() method handles the entire object graph, including all referenced
objects, automatically. It traverses the object structure recursively, serializing each
component.
How it Works: Reading an Object
ObjectInputStream ois =
new ObjectInputStream(
new FileInputStream(
"[Link]"
)
);
MyObject reconstructedObject =
(MyObject) [Link]();
[Link]();
The readObject() method reconstructs the object and all its referenced objects in
the exact order they were written, restoring the complete object graph with original
state.
Default vs. Custom Serialization
1 2 3
Default Serialization Custom Control Object Replacement
Automatically writes all non-transient Use defaultWriteObject() to explicitly Implement writeReplace() and
and non-static fields using reflection. write default fields, or readResolve() to control object
Simple to implement but offers limited putFields()/writeFields() to control replacement during serialization and
control. which fields are serialized. deserialization processes.
Security
Considerations
The Dangers of Deserialization
Remote Code Execution
Maliciously crafted serialized objects can execute arbitrary code when
deserialized, leading to complete system compromise and
unauthorized access.
Denial of Service
Large or excessively complex serialized objects can consume massive
amounts of memory and CPU resources, crashing applications or
degrading performance.
Serialization Filtering
Introduced in Java 9, this feature allows whitelisting or blacklisting
classes that can be deserialized, providing crucial security controls.
Best Practice: Never deserialize untrusted data. Always validate
input and use secure alternatives like JSON with proper validation
for external data sources.
Key Takeaways & Best Practices
Powerful Tool
Serialization is invaluable for persistence and communication between Java applications when used correctly
Proper Implementation
Always implement Serializable or Externalizable correctly, considering your specific use case
Version Control
Use serialVersionUID for maintaining compatibility across class versions during deserialization
Security Awareness
Be acutely aware of security risks, especially with untrusted input sources
Consider Alternatives
For many use cases, modern alternatives like JSON, XML, or Protocol Buffers may be safer and more portable