Serialization
Overview
Why do we need it?
Normally the maximum life time of the object is from the program start till the program end. Serialization may help to keep object alive between the program executions.
Serialized object (as a byte stream) can be saved to the file and transferred by the network.
Serialization enables Java RMI (Remote Method Invocation) to be performed.
How to make a class Serializable
The class needs to implement a marker interface to become a Serializable.
Simple code example
The example demonstrates a serializable class, which is being serialized and deserialized through saving to the file inside of the test.
Below is a test which performs serialization and deserialization of the user instance. Pay attention that transient class field height
is ignored during the process of serialization.
A source code can be found here.
Classes involved in serialization/deserialization
can write primitive types or graph of objects to an OutputStream
as a stream of bytes.
And streams can then be read using ObjectInputStream
by the method
⚠️ TODO Create a sequence diagram of serialization/deserialization.
Caveats: Inheritance and Composition
In case a class is composed of other classes, then each of these classes has to implement
java.io.Serializable
otherwise an exception NotSerializableException
will be thrown during serialization process.
On the diagram a class RootClass
can be serialized.
But during serialization of class Subclass
an exception NotSerializableException
is thrown, because one of the Subclass
fields is a nonSerializable class (and it is important that value for this field is set, otherwise a field value is null
and no exception is thrown during serialization).
There is an example of composition for serialization. example
There is an edge case when subclass implements
Serializable
, but parent class not. Link to javadoc.
Only the fields of Serializable objects are written out and restored.
In current case it means that for Child
objects, assuming both value
and name
were set to the object only name
field values will be serialized/deserialized. And there will be no Runtime exceptions in this case.
And fields of non-serializable Parent
class will be initialised using its no-args constructor (public or protected), so this constructor should be accessible to the Child
class. There is an example, which demonstrates the edge case for inheritance. example
Serial version UID
It is strongly recommended that all serializable classes explicitly declare the private field ( this field is not useful for inheritance):
Why do we need this field?
the serialization runtime associates each serializable class with a version number, so this field is a version number
if this field is not deliberately specified in serializable class
=> serialization runtime calculate default serialVersionUID for this class based on its attributes, associated access modifiers
=> when you add/modify any field in class, which is already serialized, => class will not be able to recover, because serialVersionUID generated for new class and for old serialized are different => exception java.io.InvalidClassException is thrown
this field is used during deserialization to verify that saved and loaded objects have the same attributes and thus are compatible on serialization
There is an example where fragility of serialVersionUID
is demonstrated. example
Custom serialization
⚠️ TODO
Last updated