Learnitweb

Custom serialization in Java

Consider a case where an object has username and password as fields. We don’t want password field to be serialized like username field. So we use transient with password field. As we already know, transient fields are not persisted. During serialization, use of transient may lead to data loss.

Sometimes, it is needed to serialize fields (like password) but in a different manner than the default serialization. For example, for serialization of password, encryption can be done before serialization. In such cases, custom serialization can be used.

We can implement customized serialization using following two methods:

  1. private void writeObject(ObjectOutputStream s) throws IOException – It is a callback method and is executed automatically by JVM at the time of serialization. writeObject should call the stream’s defaultWriteObject as the first thing it does to perform default serialization. The writeObject method controls what information is saved and is typically used to append additional information to the stream. Any activity during serialization, it must be defined only in this method.
  2. private void readObject(ObjectInputStream ois) throws IOException – This method will be executed automatically by JVM at the time of deserialization. The readObject method must read in everything written by writeObject in the same order in which it was written. Any activity during deserialization, it must be defined only in this method.

In the following example, we are serializing UserDetails object. Instead of demonstrating a complex encrypting algorithm, we have used a simple string ‘xyz123’. We are appending this string to the existing password. During deserialization, while reading password we are removing this string (xyz123). In this code, we have used transient with password. Still the value of password in not lost during serialization.

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

class UserDetails implements Serializable {
	private String username = "John";
	private transient String password = "test@123";
	
	private void writeObject(ObjectOutputStream os) throws Exception { 
		os.defaultWriteObject(); 
		String encryptedPwd = "xyz123" + this.password; 
		os.writeObject(encryptedPwd);
	} 
	
	private void readObject(ObjectInputStream is) throws Exception { 
		is.defaultReadObject(); 
		String encryptedPwd=(String)is.readObject(); 
		this.password = encryptedPwd.substring(6); 
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	} 
} 

public class CustomSerializationExample {
	public static void main(String args[]) throws Exception {
		UserDetails userDetails = new UserDetails(); 
		
		System.out.println("Serialization started");
		FileOutputStream fos=new FileOutputStream("test.ser"); 
		ObjectOutputStream oos=new ObjectOutputStream(fos); 
		oos.writeObject(userDetails); 
		System.out.println("Serialization ended");
		
		System.out.println("Deserialization started");
		FileInputStream fis=new FileInputStream("test.ser"); 
		ObjectInputStream ois = new ObjectInputStream(fis); 
		userDetails = (UserDetails)ois.readObject(); 
		System.out.println("Deserialization ended");
		
		System.out.println("username: "+userDetails.getUsername());
		System.out.println("password: "+ userDetails.getPassword());
	}
}

Output

Serialization started
Serialization ended
Deserialization started
Deserialization ended
username: John
password: test@123