Serialization #
Serializing an object (resp. data structure) means converting it into a form that can be stored or transmitted, and such that the object (resp. data structure) can be later reconstructed (a.k.a. deserialized).
in Java #
Java provides a native mechanism to serialize an object (including information about the type of the object). The serialization format is not (meant to be) human-readable.
The process is JVM independent, meaning that an object can be serialized on one platform and deserialized on another.
Transient #
In Java, an instance attribute can be marked with the keyword transient
.
For instance:
public class MyClass {
String serializedAttribute;
transient int transientAttribute;
...
}
Transient attributes are excluded from the serialization process (meaning that a serialized object contains no value for its transient attribute).
Warning. When an object is deserialized (i.e. converted back to an object), default values are assigned to each of its transient attributes:
null
for a reference,0
for anint
,false
for aboolean
, etc.
Serializable #
In Java:
- a value with primitive type (e.g.
int
) is serializable,- an array is serializable if its elements are serializable,
- an object is serializable if:
- its class implements the interface
Serializable
, and- each of its attributes is serializable or marked as
transient
.
Note. Implementing the interface
Serializable
does not require implementing any method.
Example. Instances of the following class are not serializable, because
Country
does not implementSerializable
.public class Country { String name; public Country(String name) { this.name = name; } }
Instances of the following class are not serializable either, because the attribute
country
has typeCountry
, which does not implementSerializable
.public class City implements Serializable { String name; int zipCode; Country country; public City(String name, int zipCode, Country country) { this.name = name; this.zipCode = zipCode; this.country = country; } }
However, if we replace
Country country;
with
transient Country country;
then instances of the class
City
become serializable, because:
- the attribute
name
has typeString
, which implementsSerializable
, and- the attribute
zipCode
has a primitive type, and- the attribute
country
is now declared as transient.Alternatively, in this example, we could have declared that
City
implementsSerializable
.
Note. Most native implementations of the Java interfaces
Collection
(ArrayList
,LinkedList
,HashSet
,TreeSet
, etc.) andMap
(HashMap
,TreeMap
, etc.) also implementSerializable
.
serialVersionUID
#
If a class implements the interface Serializable
, it is recommended to add a field:
private static final long serialVersionUID
(annotated with @Serial
)
and initialize it.
For instance:
public class City implements Serializable {
@Serial
private static final long serialVersionUID = 0;
...
}
The value is irrelevant, but is meant to be updated (by the programmer) if the (instance) attributes of the class are modified.
For an explanation, we refer to this page.
Serialization (and deserialization) methods #
The class ObjectOutputStream
allows serializing an object, with the method:
void writeObject(Object x) throws IOException
Similarly, the class ObjectInputStream
allows deserializing an object (i.e. loading it back into memory),
with the method:
Object readObject() throws IOException, ClassNotFoundException
Note. The return type of
readObject
isObject
, so the returned object needs to be cast to its appropriate data type.
Example. Let us continue with the example above (assuming that the attribute
City.country
is marked astransient
).A instance of
City
can be serialized to a file as follows:String path = "path/to/file.ser"; Country italy = new Country("Italy"); City bologna = new City("Bologna", 40100, italy); try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(path))) { out.writeObject(bologna); } catch (IOException e) { throw new RuntimeException(e); }
And deserialized as follows:
City deserializedBologna; try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(path))) { deserializedBologna = (City) in.readObject(); } catch (IOException | ClassNotFoundException e ) { throw new RuntimeException(e); } // Ouputs 'Deserialized city: { name: Bologna, zipCode: 40100, country: null }' System.out.printf( "Deserialized city: { name: %s, zipCode: %d, country: %s }", deserializedBologna.name, deserializedBologna.zipCode, deserializedBologna.country );
Observe that the attribute
country
after deserialization has valuenull
(because it is marked astransient
).