articles

Home / DeveloperSection / Articles / Java I/O: Understanding Externalizable Interface with Example

Java I/O: Understanding Externalizable Interface with Example

Samuel Fernandes 1593 26-May-2016

A program that illustrates the use of the Externalizable interface is given here. Note that the program uses Java’s security API. We need not worry about the security code while learning the importance of the Externalizable interface.

Program Code
import java.io.*;
import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
public class ExternalizableTestApp {
                     public static void main(String args[]) throws IOException {
                             try {
                                      Customer customer = new Customer(1, "1234-5678-9876");                                       System.out.println("Before saving object: ");                                       System.out.println("ID:" + customer.getId() + " CC:"                                                         + customer.getCreditCard());
                                    ObjectOutputStream outStream = new ObjectOutputStream(
                                                        new FileOutputStream("customer.dat"));                                       outStream.writeObject(customer);                                     outStream.close();
                                      ObjectInputStream inputStream = new ObjectInputStream(                                                           new FileInputStream("customer.dat"));                                     customer = (Customer) inputStream.readObject();
                                      System.out.println("After retrieving object: ");
                                      System.out.println("ID:" + customer.getId() + " CC:"                                                           + customer.getCreditCard());
                                       inputStream.close();
                             } catch (Exception ex) {
                                      ex.printStackTrace();
                             }
                     }
}
class Customer implements Externalizable {
                     private int id;
                     private String creditCard;
                     private static Cipher cipher;
                     private static SecretKeySpec skeySpec;
                     static {
                             try {
                                      createCipher();
                             } catch (Exception e) {
                                      e.printStackTrace();
                                      System.exit(0);
                             }
                     }
                     public String getCreditCard() {
                             return creditCard;
                     }
                     public int getId() {
                             return id;
                     }
                     public Customer() {
                             id = 0;
                             creditCard = "";
                     }
                     public Customer(int id, String ccNumber) {
                             this.id = id;
                             this.creditCard = ccNumber;
                     }
                     public void writeExternal(ObjectOutput out) throws IOException {
                             try {
                                      out.write(id);
                                      encrypt();
                                      out.writeUTF(creditCard);
                                      System.out.println("After encryption: ");
                                      System.out.println("ID:" + id + " CC:" + creditCard);                              } catch (Exception ex) {
                                      ex.printStackTrace();
                             }                      }
                     public void readExternal(ObjectInput in) throws IOException,
                                      ClassNotFoundException {
                             try {
                                      id = in.read();
                                      String str = in.readUTF();
                                      decrypt(str);
                             } catch (Exception ex) {
                                      ex.printStackTrace();
                             }
                     }
                     private static void createCipher() throws Exception {
                             KeyGenerator kgen = KeyGenerator.getInstance("AES");
                             kgen.init(128);
                             // Generate the secret key specs.
                             SecretKey skey = kgen.generateKey();
                             byte[] raw = skey.getEncoded();
                             skeySpec = new SecretKeySpec(raw, "AES");
                             // Instantiate the cipher
                             cipher = Cipher.getInstance("AES");
                     }
                     private void encrypt() throws Exception {
                             cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
                             byte[] buff = cipher.doFinal(creditCard.getBytes());
                             creditCard = new String(buff);
                     }
                     private void decrypt(String str) throws Exception {
                             cipher.init(Cipher.DECRYPT_MODE, skeySpec);
                             byte[] buff = cipher.doFinal(str.getBytes());
                             creditCard = new String(buff);
                     }
}
 Explanation

The main function creates an instance of the Customer object:

Customer customer = new Customer(1, "1234-5678-9876");

The first parameter to the Customer constructor is the customer ID, and the second parameter is the credit card number. We will be saving this customer information to a disk file. However, before saving the customer instance, we must encrypt the credit card information so that anybody with access to the disk file will not be able to steal the customer credit card information. The main function creates the customer.dat file for writing the customer data and then writes the Customer object by calling its writeObject method:

ObjectOutputStream outStream = new ObjectOutputStream(

new FileOutputStream("customer.dat"));

outStream.writeObject(customer);

Before the object is serialized, the Customer object ensures that its credit card field is encrypted, as explained shortly. After saving the object, the program closes the data file and reopens it for reading the saved information:

ObjectInputStream inputStream = new ObjectInputStream(

new FileInputStream("customer.dat"));

The readObject method now reads back the stored information and re-creates the customer object:

customer = (Customer) inputStream.readObject();

Before the object is fully initialized, it ensures that its credit card information is decrypted. The program prints the object’s state to the user console before saving it to disk and after retrieving it from disk. When we run the program, the following output is shown:

Before saving object:
ID:1 CC:1234-5678-9876
After encryption:
ID:1 CC:\MT?s?/?X|[YQ.
After retrieving object:
ID:1 CC:1234-5678-9876

 

The output also shows the intermediate state after the credit card field is encrypted. Now, let’s look at the implementation of the Customer class. This class implements the Externalizable interface:

class Customer implements Externalizable {

As part of the implementation, it must implement the two interface methods writeExternal and readExternal. We’ll look at the writeExternal method first:

public void writeExternal(ObjectOutput out) throws IOException {
      try {
                out.write(id);
                encrypt();
                out.writeUTF(creditCard);

 

In this method, we first write the id field to the output stream. The encrypt method encrypts the creditCard field of the Customer class. After encryption, the program writes it to disk by calling the writeUTF method of the output stream. If we examine the contents of the disk file, we’ll find only the encrypted version of the credit card information stored in the file.

The readExternal method provides the decryption of the creditCard field:

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

          try {
                   id = in.read();
                   String str = in.readUTF();
                   decrypt(str);

 

The method first reads the id, followed by the encrypted credit card information. The decrypt method decrypts this information and copies the plain text to the creditCard field of the Customer object. Thus, the program always sees the plain text (the unencrypted version) of the credit card information. However, the stored data always contains the encrypted version of this field. The readExternal and writeExternal methods do this trick transparently.

The rest of the code in the Customer class uses the security API. Be sure to refer to the security API in Java documentation for further details.


Updated 29-Nov-2017

Leave Comment

Comments

Liked By