June 29, 2022

Serialization Proxy Pattern -readResolve() and writeReplace()

In this post we’ll discuss the Serialization proxy pattern which is a more secure way to serialize an object by serializing a proxy object instead.

Need for serialization proxy pattern

Serialization in Java do have some problems like-

  1. You don’t have much control over the whole serialization process. Changing the class over time also causes compatibility problem with the serialized objects.
  2. In serialization actual object is serialized which increases the security risk. Any attacker can reconstruct a real object from the serialized state or change the stream to manipulate the object data.

With serialization proxy pattern you can secure the serialization process. Rather than the actual object a proxy object is serialized. To get a proxy object you need to create a static inner class with in a real class which also implements Serializable interface and have the same fields as the actual class.

readResolve() and writeReplace() methods in Java

You need to implement two methods readResolve() and writeReplace() for correctly implementing serialization proxy pattern.

writeReplace()- This method is implemented by the Serializable class that want to write a proxy object to the stream.

ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException;

readResolve()- Classes that need to return a replacement when an instance of it is read from the stream should implement this method. When proxy object is read from the stream then an actual object has to be returned in Serialization proxy pattern so this method has to be implemented in the proxy class.

ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;

Serialization proxy pattern Java example

Here is a class whose object has to serialized using Serialization proxy pattern so it will have a static inner class and readResolve() and writeReplace() methods are implemented too.

import java.io.Serializable;

public class Employee implements Serializable{
  private static final long serialVersionUID = -8690951276691191306L;
  private String name;
  private String dept;
  private int salary;
  private int age;
  Employee(String name, String dept, int salary, int age){
    this.name = name;
    this.dept = dept;
    this.salary = salary;
    this.age = age;
  }
	
  //writeReplace method for the proxy pattern	
  private Object writeReplace() {
    System.out.println("In writeReplace() method");
    return new EmployeeProxy(this);
  }

  private void readObject(ObjectInputStream ois) throws InvalidObjectException{
    throw new InvalidObjectException("Use proxy class");
  }

  private static class EmployeeProxy implements Serializable{
    private String name;
    private String dept;
    private int salary;
    private int age;
    EmployeeProxy(Employee emp){
      this.name = emp.name;
      this.dept = emp.dept;
      this.salary = emp.salary;
      this.age = emp.age;
    }
    // readResolve method in Proxy class
    private Object readResolve() {
      System.out.println("In readResolve() method");
      return new Employee(name, dept, salary, age);
    } 
  }	
  // setters and getters
}

Some important points you should notice in this class are-

  1. EmployeeProxy class is defined as a static inner class. Proxy class also implements Serializable interface.
  2. Constructor of the EmployeeProxy class takes Employee object as argument and creates a proxy object using it. While creating proxy object if need be you can also encrypt data to make it more secure.
  3. Employee class implements writeReplace() method that returns an instance of proxy class.
  4. EmployeeProxy class implements readResolve() method and return Employee object.
  5. As an added precaution also implement readObject() method to throw an exception. With that there is no chance to fabricate Employee object from the stream.

Here is a class with methods to Serialize and deserialize an object.

public class SerializationDemo {

  public static void main(String[] args) {
    Employee emp = new Employee("Ryan", "IT", 7500, 35);
    final String fileName = "F:\\knpcode\\emp.ser";
    serialzeObject(emp, fileName);
    
    /// Do null check here
    Employee e = (Employee)deSerializeObject(fileName);
    System.out.println("Name- " + e.getName());
    System.out.println("Dept- " + e.getDept());
    System.out.println("Salary- " + e.getSalary());
    System.out.println("Age- " + e.getAge());
  }	
	
  // Method to serialize object 
  public static void serialzeObject(Object obj, String fileName) { 
    try(ObjectOutputStream outStream = new ObjectOutputStream(new FileOutputStream(fileName))){
      outStream.writeObject(obj); 
    } catch (IOException e) { 
      // TODO Auto-generated
      e.printStackTrace(); 
    } 
  }
	 	
  // Method to deserialize object
  public static Object deSerializeObject(String fileName){
    Object obj = null;
    try(ObjectInputStream inStream = new ObjectInputStream(new FileInputStream(fileName))){
      obj = inStream.readObject();	 			
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (ClassNotFoundException e) {
      System.out.println("No class found for serialization");
      e.printStackTrace();
    }
    return obj;
  }
}
Output
In writeReplace() method to serialize proxy
In readResolve() method to get actual object
Name- Ryan
Dept- IT
Salary- 7500
Age- 35

That's all for the topic Serialization Proxy Pattern -readResolve() and writeReplace(). If something is missing or you have something to share about the topic please write a comment.


You may also like

No comments:

Post a Comment