- Details
- Written by Nam Ha Minh
- Last Updated on 30 July 2019   |   Print Email
This article helps you understand about externalization in Java with code examples. You will be able to implement externalization in your Java programs.
1. What is Externalization in Java?
In
serialization, the Java Virtual Machine is totally responsible for the process of writing and reading objects. This is useful in most cases, as the programmers do not have to care about the underlying details of the serialization process. However, the default serialization does not protect sensitive information such as passwords and credentials, or what if the programmers want to secure some information during the serialization process?Thus externalization comes to give the programmers full control in reading and writing objects during serialization.
2. The Externalizable Interface
When you want to control the process of reading and writing objects during the serialization and de-serialization process, have the object’s class implemented the
java.io.Externalizable interface. Then you implement your own code to write object’s states in the
writeExternal() method and read object’s states in the
readExternal() method. These methods are defined by the
Externalizableinterface as follows:
- writeExternal(ObjectOutput out): The object implements this method to save its contents by calling the methods of DataOutput for its primitive values or calling the writeObject method of ObjectOutput for objects, strings, and arrays.
- readExternal(ObjectInput in): The object implements this method to restore its contents by calling the methods of DataInput for primitive types and readObject for objects, strings and arrays.
Suppose that you have a class
User, then implement externalization for this class as shown in the following example:
import java.io.*;
/**
* Externalization example
* @author www.codejava.net
*/
public class User implements Externalizable {
// attributes
// methods
// externalization methods:
public void writeExternal(ObjectOutput out) {
// implement your own code to write objects of this class
}
public void readExternal(ObjectInput in) {
// implement your own code to read serialized objects of this class
}
}
Now, let’s see how to implement the
writeExternal() and
readExternal() methods in details.
Suppose that the
User class has the following attributes:
import java.util.*;
import java.io.*;
/**
* Externalization example
* @author www.codejava.net
*/
public class User implements Externalizable {
public static final long serialVersionUID = 1234L;
// attributes
private int code;
private String name;
private String password;
private Date birthday;
private int socialSecurityNumber;
public User() {
}
// methods (getters and setters)
public int getCode() {
return this.code;
}
public void setCode(int code) {
this.code = code;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return this.password;
}
public void setPassword(String password) {
this.password = password;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Date getBirthday() {
return this.birthday;
}
public void setSocialSecurityNumber(int ssn) {
this.socialSecurityNumber = ssn;
}
public int getSocialSecurityNumber() {
return this.socialSecurityNumber;
}
}
NOTE: It’s strongly recommended that all serializable classes define the
serialVersionUID constant as declared in the
User class above:
public static final long serialVersionUID = 1234L;
This helps the de-serialization process keeps re-constructing the objects correctly when the serializable classes get changed overtime, and avoid the
InvalidClassException.
3. Implementing writeExternal() method
As the
writeExternal() method takes an
ObjectOutput, we can use its method to write object’s states into the underlying stream follow these rules:
- For primitive types, use the writeXXX() methods of the DataOutput interface, such as writeBoolean(), writeByte(), writeInt(), writeLong(), etc.
- For object types (Strings, arrays, your custom classes), use the writeObject() method.
Following the above rules, we implement the
writeExternal() method of the
User class above like the following code:
public void writeExternal(ObjectOutput out) throws IOException {
out.writeInt(code);
out.writeObject(name);
// write empty password:
out.writeObject("");
out.writeObject(birthday);
}
As you can see, we serialize the following attributes: code, name, password and birthday. For security purpose, password is cleared and
socialSecurityNumber is not serialized. This gives you the ideas of how we can control the process of serialization by implementing the
Externalizable interface.
4. Implementing readExternal() method
As the
readExternal() method takes an
ObjectInput, we can use its method to read object’s states from the underlying stream follow these rules:
- For primitive types, use the readXXX() methods of the DataInput interface, such as readBoolean(), readByte(), readInt(), readLong(), etc.
- For object types (Strings, arrays, your custom classes), use the readObject() method.
Following the above rules, we implement the
readExternal() method of the
User class above like the following code:
public void readExternal(ObjectInput in) throws ClassNotFoundException, IOException {
this.code = in.readInt();
this.name = (String) in.readObject();
this.password = (String) in.readObject();
this.birthday = (Date) in.readObject();
}
As you can see, we de-serialize the following attributes: code, name, password and birthday. The
socialSecurityNumber is not de-serialized for security purpose. This gives you the ideas of how we can control the process of de-serialization by implementing the
Externalizable interface.
5. Java Externalization Example Program
Here’s the full source code of the demo program:
import java.util.*;
import java.io.*;
/**
* Externalization Demo Program.
* @author www.codejava.net
*/
public class ExternalizationDemo {
private String filePath = "user.ser";
public void serialize() throws IOException {
User user = new User();
user.setCode(123);
user.setName("Tom");
user.setBirthday(new Date());
user.setPassword("secret123");
user.setSocialSecurityNumber(1234567890);
// serialize object's state
FileOutputStream fos = new FileOutputStream(filePath);
ObjectOutputStream outputStream = new ObjectOutputStream(fos);
outputStream.writeObject(user);
outputStream.close();
System.out.println("User's details before serialization:\n" + user);
System.out.println("Serialization done");
}
public void deserialize() throws ClassNotFoundException, IOException {
FileInputStream fis = new FileInputStream(filePath);
ObjectInputStream inputStream = new ObjectInputStream(fis);
User user = (User) inputStream.readObject();
inputStream.close();
System.out.println("User's details afeter de-serialization:\n" + user);
}
public static void main(String[] args)
throws ClassNotFoundException, IOException {
ExternalizationDemo demo = new ExternalizationDemo();
demo.serialize();
System.out.println("\n=============\n");
demo.deserialize();
}
}
And override the
toString() method in the
User class:
public String toString() {
String details = "Code: " + code;
details += "\nName: " + name;
details += "\nBirthday: " + birthday;
details += "\nPassword: " + password;
details += "\nSSN: " + socialSecurityNumber;
return details;
}
Run the above program and we have the following output:
User's details before serialization:
Code: 123
Name: Tom
Birthday: Sat Mar 19 15:12:27 ICT 2016
Password: secret123
SSN: 1234567890
Serialization done
=============
User's details afeter de-serialization:
Code: 123
Name: Tom
Birthday: Sat Mar 19 15:12:27 ICT 2016
Password:
SSN: 0
As you can see in the output, the password gets blank and social security number is reset after de-serialization.
API References:
Related Tutorials:
Other Java File IO Tutorials:
About the Author:
Nam Ha Minh is certified Java programmer (SCJP and SCWCD). He started programming with Java in the time of Java 1.4 and has been falling in love with Java since then. Make friend with him on
Facebook and watch
his Java videos you YouTube.