Serialization in Java with example
What is Serialization?
Serialization is the process of encoding an object to byte stream and reverse of it is called deserialization.It is platform independent process which means you can serialize the object in one JVM and can transport the object over network and / or store it in filesystem and then deserialize it in other or on same JVM.
Class needs to implements marker interface Serializable
in order to make their object to be eligible for Serialization.
fields with transient
and/or static
modifiers are not serialized by regular serialization process.
ObjectInputStream
and ObjectOutputStream
are high level stream classes which have methods to serialize and de-serialize Java objects.
ObjectOutputStream
class has many write methods but the method that is usually used method is:
public final void writeObject(Object obj) throws IOException
ObjectInputStream
class has many read methods but the method that is usually used method is:
public final Object readObject() throws IOException, ClassNotFoundException
Basic Serialization Example
Let's first define Dog
pojo and then use ObjectInputStream
and ObjectOutputStream
for de-serialization and serialization.
public class Dog implements Serializable { private static final long serialVersionUID = 8661314562327474362L; private int height; private String name; // getters/ setters/ toString/ constructors } public class SimpleSerializationExample { public static void main(String[] args) { Dog dog = new Dog(50, "Titan"); // create dog object with height 50 and name Titan System.out.println("Before Serialization"); System.out.println(dog); try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("dog.ser"))) { oos.writeObject(dog);// serialize the dog object } catch (IOException ioEx) { /* Don't Swallow exception in real projects */ } dog = null; // let clear old dog object reference try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("dog.ser"))) { dog = (Dog) ois.readObject();// deserialize dog object } catch (IOException | ClassCastException | ClassNotFoundException ex) { /* Don't Swallow exception in real projects */ } System.out.println("After Serialization"); System.out.println(dog); } }
writeObject()
method of ObjectOutputStream
will throw run-time exception java.io.NotSerializableException
The above class was pretty straightforward with two primitive instance members. But, in real world could there be a case when
case 1: super class is not serializable but sub-class is.
case 2: You class have composed object of another class which doesn't implements Serializable
interface.
case 1: super class is not serializable but sub-class is
There could be situation when you are extending some class which is not serializable but you want the sub-class be serializable. It is only possible if your super-class has
- default no-args constructor.
- supports ways to initialize safely the shared fields.
Serializable
interface then the inherited fields in the sub-class will be initialized to their default values and the Constructor will be called from first instance of non-serializable class till all the super class constructors are run. But in case of serializable class, then constructor will never run at the time of deserialization.case 2: You have composed of object of another class which doesn't support serialization
The only solution is to mark that field reference as transient
and do custom serialization for that.
writeObject and readObject to rescue for case 1 and case 2
Java serialization have special mechanism just for this. It has a set of private methods you can implement in your serializable class which will be invoked automatically during serilization and deserilization. The signature of these methods are :
private void writeObject(ObjectOutputStream os) { //Your custom code for serilization goes here } private void readObject(ObjectInputStream is) { //Your custom code for deserilization goes here }
These methods let you step into the middle of serialization and deserialization.
Let's move to example.
public class Collar { private int size; // getters/ setters/ toString } public class Dog implements Serializable { private static final long serialVersionUID = 6870143058315212650L; private int height; private String name; private transient Collar myCollar; //getters/ setters/ toString private void writeObject(ObjectOutputStream os) throws IOException { try { os.defaultWriteObject();// lets first have default serialization happens os.writeInt(myCollar.getSize()); // save custom values } catch (IOException ex) { } } private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException { try { is.defaultReadObject();// lets first have default deserialization happens myCollar = new Collar(is.readInt()); // custom read values } catch (IOException | ClassNotFoundException ex) { } } } public class SimpleSerializationExample { public static void main(String[] args) { Dog dog = new Dog(1, "BuBu", new Collar(5)); // create dog object with height 50 and name Titan System.out.println("Before Serialization"); System.out.println(dog); try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("dog_collar.ser"))) { oos.writeObject(dog);// serialize the dog object } catch (IOException ioEx) { /* Don't Swallow exception in real projects */ } dog = null; // let clear old dog object reference try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("dog_collar.ser"))) { dog = (Dog) ois.readObject();// deserialize dog object } catch (IOException | ClassCastException | ClassNotFoundException e) { /* Don't Swallow exception in real projects */ } System.out.println("After Serialization"); System.out.println(dog.toString());
} }Explanation
- Line 15 and 22 declares writeObject and readObject methods in the
Dog
class. - Line 17 invoked defaultWriteObject() of
ObjectOutputStream
from writeObject(). We are telling JVM to perform the normal serialization. Line 18 did custom writing to the serialized object. - Line 24 invoked defaultReadObject() of
ObjectInputStream
from readObject() to handle normal serialization and then our custom deserialization starts at Line 25.
ObjectOutputStream
because it saves in the sequence we write it. If we don't do so, we may end up in half-baked or wrongly deserialized object.
No comments :
Post a Comment