Serialization in Java
This post will discuss serialization in Java with the help of Serializable interface and Apache Commons Lang’s SerializationUtils class.
As seen in the previous post, Deep Copy using Object.clone() is very tedious to implement, error-prone, and difficult to maintain. Also, the Object.clone() method will not work if we try to assign a value to a final field.
One solution to address these issues is to use Java Object Serialization (JOS). Serialization is the process of converting an object into a sequence of bytes and rebuilding those bytes later into a new object. In other words, Serialization is used to persist an object.
1. Serializable Interface
Java provides automatic serialization, which requires that the object be marked by implementing the java.io.Serializable interface. Implementing the interface marks the class as “okay to serialize”, and Java then handles serialization internally.
There are no serialization methods defined on the Serializable interface, but we can use ObjectOutputStream.writeObject() method to convert the object into a serialized form, and a corresponding ObjectInputStream.readObject() method to recreate an object from that representation. The result will be a completely distinct object, with completely distinct referenced objects.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
import java.io.*; import java.util.Arrays; import java.util.HashSet; import java.util.Set; class Subjects implements Serializable { private Set<String> subjects; public Subjects() { subjects = new HashSet<>( Arrays.asList("Maths", "Science", "English", "History") ); } @Override public String toString() { return subjects.toString(); } } class Student implements Serializable { private String name; private int age; private Subjects subjects; public Student(String name, int age) { this.name = name; this.age = age; subjects = new Subjects(); } @Override public String toString() { return Arrays.asList(name, String.valueOf(age), subjects.toString()) .toString(); } } // Demonstrate deep copy of objects using `Serializable` interface class Main { public static void main(String[] args) { Student student = new Student("John Snow", 25); Student clone = null; try { // Create a byte array output stream ByteArrayOutputStream bos = new ByteArrayOutputStream(); // Use byte array output stream to create an object output stream ObjectOutputStream oos = new ObjectOutputStream(bos); // Serialization – Pass the object that we want to copy to the // ObjectOutputStream's `writeObject()` method oos.writeObject(student); oos.flush(); // toByteArray creates & returns a copy of the stream's byte array byte[] bytes = bos.toByteArray(); // Create a byte array input stream ByteArrayInputStream bis = new ByteArrayInputStream(bytes); // Use byte array input stream to create an object input stream ObjectInputStream ois = new ObjectInputStream(bis); // deserialize the serialized object using ObjectInputStream's // `readObject()` method and typecast it to the class of the object clone = (Student) ois.readObject(); System.out.println(clone.toString()); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } |
Output:
[John Snow, 25, [Science, Maths, English, History]]
Well, this approach also has some limitations and issues:
- It requires the object being copied and all its object references to be serializable. So all involved classes should implement the
java.io.Serializableinterface. - Serialization will not work on transient fields.
- There will be vast difference in the performance as compared to using
Object.clone(). A deep copy requires both serializing and deserializing, which are very time-consuming, and Java’s byte array stream implementation is also slow. - We know that the Singleton pattern restricts a class’s instantiation to one object, i.e., a class needs to have only one instance. But Serialization can break this contract. The new object created by Serialization will not be unique. To get around this undesired behavior, we can use the
readResolve()method to enforce singletons. ThereadResolvemethod is called afterObjectInputStreamhas read an object from the stream and is preparing to return it to the caller. It basically replaces the object with the singleton instance (if any).
2. Using Apache Commons Lang
We can also use the SerializationUtils class provided by Apache Commons Lang to assist with the serialization process. It provides the following methods to help with serialization and deserialization:
serialize(): Serializes an object to abyte[]array. It takes the object to be serialized as input and returns abyte[]array.deserialize(): Deserializes a single Object from an array of bytes. It takes the serialized object as input (which must not be null) and returns the deserialized object.
SerializationUtils requires the object being copied and all its objects references to implement the java.io.Serializable interface, and it won’t work on transient fields.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
import org.apache.commons.lang3.SerializationUtils; import java.io.Serializable; import java.util.Arrays; import java.util.HashSet; import java.util.Set; class Subjects implements Serializable { private Set<String> subjects; public Subjects() { subjects = new HashSet<>( Arrays.asList("Maths", "Science", "English", "History") ); } @Override public String toString() { return subjects.toString(); } } class Student implements Serializable { private String name; private int age; private Subjects subjects; public Student(String name, int age) { this.name = name; this.age = age; subjects = new Subjects(); } @Override public String toString() { return Arrays.asList(name, String.valueOf(age), subjects.toString()) .toString(); } } // Demonstrate deep copy of objects using Apache Commons Lang // `SerializationUtils` class class Main { public static void main(String[] args) { Student student = new Student("John Snow", 25); try { byte[] bytes = SerializationUtils.serialize(student); Student clone = (Student) SerializationUtils.deserialize(bytes); System.out.println(clone.toString()); } catch (SerializationException ex) { // if the serialization fails ex.printStackTrace(); } catch (IllegalArgumentException ex) { // if the bytes array is null ex.printStackTrace(); } } } |
Output:
[John Snow, 25, [Science, Maths, English, History]]
That’s all about serialization in Java.
Also See:
Thanks for reading.
To share your code in the comments, please use our online compiler that supports C, C++, Java, Python, JavaScript, C#, PHP, and many more popular programming languages.
Like us? Refer us to your friends and support our growth. Happy coding :)