Java – Externalizable interface with example

In this article, we will discuss externalizable interface with an example to save and restore an object in a customized way

Also, we will discuss advantage of using Externalizable over Serializable in detail

In next article we will cover important points while discussing difference between Externalizable and Serializable interfaces

1. Serializable interface :

Although, we have discussed serializable interface in detail in one of the previous article, here we will list out what are the various things that affects performance

  • While serializable implemented class does the necessary job of Serialization and de-serialization in saving & restoring object but it saves altogether all member variables of an object
  • This way, even if programmer requires only couple of member variables of an Object to be saved, Serializable doesn’t allow those kinds of flexibility
  • That is no flexibility saving & restoring partial object
  • It is time consuming in saving and restoring object during both serialization and de-serialization process
  • As JVM controls complete serialization and de-serialization process and programmer has nothing to do with serializable interface
  • With transient modifier also, we can stop serializing original value but still that particular member variable get saved to file storage although with default value
  • Due to saving and restoring of all member variables of an Object, even if programmer requires only couple of variables to be saved/restored back, there is big performance hit

To overcome above listed performance issue with serializable, we have to serialize with externalizable interface which is sub-interface of Serializable interface

1.1 Advantage of Externalizable over Serializable :

  • Allows saving/restoring partial object i.e.; 2 or 3 member variables of an object out of total object
  • As programmer has to code/write custom logic for serialization and de-serialization process, so write/code logic to save/restore those variables which is required
  • This way, there is performance boost relatively when comparing with serializable interface
  • Transient variable is not required as programmer has control over saving/restoring object and can easily ignore those variables whose value is secure or need to kept very secret
  • By saving/restoring partial object instead of total object, time consumption decreases i.e.; time is saved in externalizable interface

2. Externalizable interface :

  • Externalizable interface is sub-interface of Serializable interface
  • Present in java.io package
  • Fully qualified class name is java.io.Externalizable
  • It has got 2 methods namely, writeExternal(); and readExternal();
  • Method 1: with writeExternal(ObjectOutput out) method, programmer has to explicitly code/write logic for saving only those required variables to file storage
  • Method 2: with readExternal(ObjectInput in) method, programmer has to explicitly code/write logic for restoring object back from file storage
  • Note: class implementing externalizable interface should definitely consist of a public no-arg constructor, otherwise InvalidClassException is thrown
  • Design choice: This is the best suit; when partial object or few member variables of an object need to be serialized to file storage, otherwise still serializable interface is a good option for saving total object

Q) Write complete method signature of 2 methods ?

  • Method signature :
// writeExternal method
public void writeExternal(ObjectOutput out) throws IOException {

} 

// readExternal method
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {

}

3. Example on Externalizable interface:

  1. Customer class implementing Externalizable interface
  2. Serialization and De-serialization using Externalizable interface
  3. Exception scenario

3.1 Customer class implementing Externalizable interface :

  • Below Customer class consists of 4 member variables, out of which 2 variables need to be serialized and other variables are discarded
  • In Externalization, programmer need to implement/override 2 methods for saving/restoring object
  • For partial serialization, we have to override 2 methods namely,
    writeExternal(); –> for saving/writing in serialization process
    readExternal(); –> for restoring during de-serialization process

3.1.1 Custom Serialization:

  • During serialization inside writeExternal(); method, programmer has to code/write custom logic to save/persist 2 member variables

3.1.2 Custom De-Serialization:

  • During de-serialization inside readExternal(); method, programmer has to code/write custom logic to read 2 variable and then finally assigning to actual member variables

Customer.java

package in.bench.resources.externalization;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;

// class implementing Externalizable interface
class Customer implements Externalizable {

	// member variables for Customer
	int customerId;
	String customerName;
	int customerAge;
	String customerSSN;

	// default public no-arg constructor
	public Customer() {
		System.out.println("public no-arg constructor is must for "
				+ "Externalizable, "
				+ "while restoring object back from file storage");
	}

	// 4-arg parameterized constructor for Customer
	public Customer(int customerId, String customerName,
			int customerAge, String customerSSN) {
		super();
		this.customerId = customerId;
		this.customerName = customerName;
		this.customerAge = customerAge;
		this.customerSSN = customerSSN;
	}

	@Override
	public void writeExternal(ObjectOutput out) throws IOException {

		// saving to file storage
		out.writeInt(customerId);
		out.writeObject(customerName);
	}

	@Override
	public void readExternal(ObjectInput in)
			throws IOException, ClassNotFoundException {

		// restoring variables, as per order of serialization
		int tempCustId = in.readInt();
		String tempCustName = (String) in.readObject();

		// assigning restored values to member variables
		customerId = tempCustId;
		customerName = tempCustName;
	}

	// to print nicely - customer object
	@Override
	public String toString() {
		return "Customer [customerId=" + customerId
				+ ", customerName=" + customerName
				+ ", customerSSN=" + customerSSN
				+ ", customerAge=" + customerAge
				+ "]";
	}
}

3.2 Serialization and De-serialization using Externalizable interface :

  • This program is the test class to write/save customer object to file storage and then restoring for reading customer object
  • 1st part explains, complete serialization process
  • 2nd explains, complete de-serialization process
  • Note: class that needs to be serialized is implementing Externalizable interface unlike Serializable interface in earlier examples

CustomerSerialization.java

package in.bench.resources.externalization;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class CustomerSerialization {

	public static void main(String[] args) {

		// create an customer object using 4-arg constructor
		Customer serializeCustomer =
				new Customer(102, "NK", 19, "SSN-78087");

		// creating output stream variables
		FileOutputStream fos = null;
		ObjectOutputStream oos = null;

		// creating input stream variables
		FileInputStream fis = null;
		ObjectInputStream ois = null;

		// creating customer object reference
		// to hold values after de-serialization
		Customer deSerializeCustomer = null;

		try {
			// for writing or saving binary data
			fos = new FileOutputStream("Customer.ser");

			// converting java-object to binary-format
			oos = new ObjectOutputStream(fos);

			// writing or saving customer object's value to stream
			oos.writeObject(serializeCustomer);
			oos.flush();
			oos.close();

			System.out.println("Externalization: "
					+ "Customer object saved to Customer.ser file\n");

			// reading binary data
			fis = new FileInputStream("Customer.ser");

			// converting binary-data to java-object
			ois = new ObjectInputStream(fis);

			// reading object's value and casting to Customer class
			deSerializeCustomer = (Customer) ois.readObject();
			ois.close();

			System.out.println("Externalization: Customer object "
					+ "de-serialized from Customer.ser file\n");
		}
		catch (FileNotFoundException fnfex) {
			fnfex.printStackTrace();
		}
		catch (IOException ioex) {
			ioex.printStackTrace();
		}
		catch (ClassNotFoundException ccex) {
			ccex.printStackTrace();
		}

		// printing customer object to console using toString() method
		System.out.println("Printing customer values from "
				+ "de-serialized object... \n" + deSerializeCustomer);
	}
}

Output:

Externalization: Customer object saved to Customer.ser file

public no-arg constructor is must for Externalizable,
while restoring object back from file storage
Externalization: Customer object de-serialized from Customer.ser file

Printing customer values from de-serialized object...
Customer [customerId=102, customerName=NK, customerSSN=null, customerAge=0]

Explanation:

  • Only two variables is persisted and restored back and other variables are discarded as it isn’t required
  • So, when we print customer object using overridden toString() method, only customer Id and customer Name is restored and other variables assigned to default values
  • Like, null for customer SSN number and 0 for customer age
  • Note: public no-arg constructor is very must while restoring object back from file storage
  • Otherwise, InvalidClassException is thrown

3.3 Exception scenario :

  • Let us tweak above example by removing public no-arg constructor
  • try to serialize & de-serialize customer object

Output:

Externalization: Customer object saved to Customer.ser file

java.io.InvalidClassException: in.bench.resources.externalization
.Customer; no valid constructor
	at java.io.ObjectStreamClass$ExceptionInfo
.newInvalidClassException(ObjectStreamClass.java:150)
	at java.io.ObjectStreamClass
.checkDeserialize(ObjectStreamClass.java:790)
	at java.io.ObjectInputStream
.readOrdinaryObject(ObjectInputStream.java:1775)
	at java.io.ObjectInputStream
.readObject0(ObjectInputStream.java:1351)
	at java.io.ObjectInputStream
.readObject(ObjectInputStream.java:371)
	at in.bench.resources.externalization
.CustomerSerialization.main(CustomerSerialization.java:52)
Printing customer values from de-serialized object...
null

Related Articles:

References:

Happy Coding !!
Happy Learning !!

Java - Serializable v/s Externalizable
Java - Serialization with Inheritance