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:
nullfor a reference,0for anint,falsefor 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
Serializabledoes not require implementing any method.
Example. Instances of the following class are not serializable, because
Countrydoes 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
countryhas 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
Citybecome serializable, because:
- the attribute
namehas typeString, which implementsSerializable, and- the attribute
zipCodehas a primitive type, and- the attribute
countryis now declared as transient.
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 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
readObjectisObject, 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.countryis marked astransient).A instance of
Citycan 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
countryafter deserialization has valuenull(because it is marked astransient).