Serialization in Java provides a pretty good default implementation for serializing and deserializing an object. All you need to do is to implement Serializable interface and the whole process is automatic for you.
But, what if you want to control the process of serialization, you have some fields in your object which hold confidential information and you don’t want to serialize those fields or a sub-object with in your object graph doesn’t need to be serialized. That’s when you can use Externalizable interface in Java for custom serialization and deserialization.
Externalizable interface in Java
Externalizable interface extends the Serializable interface (which is a
marker interface) and adds two methods writeExternal()
and readExternal()
.
When you use Externalizable for your serialization, you will implement Externalizable interface and implement writeExternal() and readExternal() methods. These two methods will be called while serializing and deserializing respectively.
General form of writeExternal() and readExternal()
- readExternal(ObjectInput in)- The object implements the readExternal method to restore its contents by calling the methods
of
DataInput
for primitive types andreadObject
for objects, strings and arrays. - writeExternal(ObjectOutput out)- The object implements the writeExternal method to save its contents by calling the methods of
DataOutput
for its primitive values or calling thewriteObject
method of ObjectOutput for objects, strings, and arrays.
Refer Serialization in Java to see another way, using readObject and writeObject to control the process of serialization.
Serialization process when Externalizable interface is used
Each object to be stored is tested for the Externalizable interface. If the object supports Externalizable, the writeExternal
method is called. If the object does not support Externalizable and does implement Serializable, the object is saved
using ObjectOutputStream.
When an Externalizable object is reconstructed, an instance is created using the public no-arg constructor, then the
readExternal
method called. Serializable objects are restored by reading them from an ObjectInputStream.
Externalizable interface Java example
Let’s see an example where we have a class called User
in which pwd
field is there that you don’t want to convert into
bytes. Though that can also be done by marking it as
transient but here let us see how Externalizable can be used to control the serialization.
User class
import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; public class User implements Externalizable { private String userName; private int id; private String pwd; // no-arg constructor **Required** public User(){ System.out.println("In no-arg constructor"); } public User(String userName, int id, String pwd){ System.out.println("In constructor with args"); this.userName = userName; this.id = id; this.pwd = pwd; } public String getUserName() { return userName; } public int getId() { return id; } public String getPwd() { return pwd; } @Override public void writeExternal(ObjectOutput out) throws IOException { System.out.println("In writeExternal method"); out.writeObject(userName); out.writeInt(id); } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { System.out.println("In readExternal method"); userName = (String)in.readObject(); id = in.readInt(); } }
ExternalizableDemo class
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class ExternalizableDemo { public static void main(String[] args) { User user = new User("TestUser", 1, "pwd"); try { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("test.ser")); oos.writeObject(user); oos.close(); ObjectInputStream ois = new ObjectInputStream(new FileInputStream("test.ser")); user = (User)ois.readObject(); ois.close(); System.out.println("UserName " + user.getUserName() + " id " + user.getId() + " pwd " + user.getPwd()); } catch (IOException | ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
Output
In constructor with args In writeExternal method In no-arg constructor In readExternal method UserName TestUser id 1 pwd null
Here you can see that writeExternal() and readExternal() methods are called for serializing and deserializing the object. Now it is upto you to provide implementation for serialization in writeExternal() method where pwd field is excluded.
Points to note here are-
- A default no-arg constructor has to be there while using externalizable as object is created using no-arg constructor while deserializing and then the object is initialized using the logic in readExternal() method. Note that it is different from default serialization where object is reconstituted using the byte stream and constructor is not called.
- Order that is used in writeExternal() method for writing the fields should be maintained in readExternal() method.
Externalizable with inheritance
One scenario where Externalizable can be used quite effectively is in a parent-child relationship where parent class doesn’t implement the serializable interface but you want the fields that are there in the parent class to be serialized too.
In this case if you create an object of the child class and serialize it using default serialization. Then deserializing it won’t give you any value for the fields which child class object gets by virtue of extending parent class.
Let’s say we have a classA which is the super class and classB which extends classA.
ClassA
public class ClassA { private int deptId; private String deptName; public int getDeptId() { return deptId; } public void setDeptId(int deptId) { this.deptId = deptId; } public String getDeptName() { return deptName; } public void setDeptName(String deptName) { this.deptName = deptName; } }
ClassB
import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; public class ClassB extends ClassA implements Externalizable{ private String empId; private String empName; public String getEmpId() { return empId; } public void setEmpId(String empId) { this.empId = empId; } public String getEmpName() { return empName; } public void setEmpName(String empName) { this.empName = empName; } @Override public void writeExternal(ObjectOutput out) throws IOException { System.out.println("In writeExternal method"); //Writing parent class ClassA fields out.writeInt(getDeptId()); out.writeObject(getDeptName()); // Writing child class fields out.writeObject(getEmpId()); out.writeObject(getEmpName()); } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { System.out.println("In readExternal method"); // Setting parent class fields setDeptId(in.readInt()); setDeptName((String)in.readObject()); // Setting child class fields setEmpId((String)in.readObject()); setEmpName((String)in.readObject()); } }
Test class
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class ExternalizableDemo { public static void main(String[] args) { final String fileName = "D://test.ser"; ClassB objb = new ClassB(); objb.setDeptId(1); objb.setDeptName("Finance"); objb.setEmpId("E001"); objb.setEmpName("Ram"); try { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(fileName)); oos.writeObject(objb); oos.close(); ObjectInputStream ois = new ObjectInputStream(new FileInputStream(fileName)); objb = (ClassB)ois.readObject(); ois.close(); System.out.println("DeptId " + objb.getDeptId() + " DeptName " + objb.getDeptName() + " EmpId " + objb.getEmpId() + " EmpName "+ objb.getEmpName()); } catch (IOException | ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
Output
In writeExternal method In readExternal method DeptId 1 DeptName Finance EmpId E001 EmpName Ram
Since you can control what is serialized and how, you can make sure that all the fields of super class ClassA are also serialized and deserialized in the writeExternal() and readExternal() methods.
That's all for this topic Externalizable Interface in Java. If you have any doubt or any suggestions to make please drop a comment. Thanks!
>>>Return to Java Advanced Tutorial Page
Related Topics
You may also like-