As we’ve learned about serialization we’ve discussed how the JVM defines a default way to serialize objects when their classes implement the Serializable
interface. Can we modify this default process? As a matter of fact we can by implementing the methods readObject()
and writeObject()
in our class!
Let’s look at some code that implements readObject()
and writeObject()
:
public class DateOfBirth { private int month; private int day; private int year; // constructors and getters } public class Person implements Serializable { private String name; private DateOfBirth dateOfBirth; private void writeObject(java.io.ObjectOutputStream stream) throws IOException{ stream.writeObject(this.name); stream.writeInt(this.dateOfBirth.getMonth()); stream.writeInt(this.dateOfBirth.getDay()); stream.writeInt(this.dateOfBirth.getYear()); } private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException{ this.name = (String) stream.readObject(); int month = (int) stream.readInt(); int day = (int) stream.readInt(); int year = (int) stream.readInt(); this.dateOfBirth = new DateOfBirth(month, day, year); } }
In the example above:
- We’ve got two classes
Person
which implementsSerializable
andDateOfBirth
which does not. Person
has a reference field of typeDateOfBirth
.- If we were to use the default serialization process we would get a
NotSeriliazableException
becauseDateOfBirth
does not implementSerializable
. - We implement
writeObject()
, which must throwIOException
, to serialize aDataOfBirth
object by manually serializing all of its fields separately. We also serialize the serializableString
field. - We implement
readObject()
, which must throwIOException
andClassNotFoundException
, to deserialize aPerson
object by reading all theint
fields that are a part ofDataOfBirth
and creating a newDateOfBirth
object with the provided constructor. This new object is used to set thedateOfBirth
field inPerson
.
Most times the default process of serialization is enough as long as all references implement Serializable
. The implementation of readObject()
and writeObject()
is especially useful when you have a reference field that does not or cannot implement Serializable
. You could also potentially handle static
field values if you needed to persist them but this is not a good practice as a static
field should belong to a class and not an object.
Let’s practice implementing our own custom serialization and deserialization methods.
Instructions
The class Car
has a non serializable Engine
reference field named engine
and cannot be serialized currently. Lets fix that!
In the class Car
, complete the implementation of writeObject()
to serialize the fields (state) of engine
using the ObjectOutputStream stream
methods. Use the provided public
getters to access engine
fields.
We’ve customized the serialization of a non serializable field in Car
and we need to be able to desirialize Engine
fields back into an engine
object.
In the class Car
, complete the implementation of readObject()
to desirialize all Car
fields using the ObjectInputStream stream
methods. Create local double
variable named liters
and int
cylinders
to store the serialized Engine
fields. Use the provided Engine
constructor to initialize the engine
reference field with liters
and cylinders
.