Friday, 26 August 2016

Restrict a class from serialization, but super class is serialized

Suppose you had scenario like below.
a.   There is a class Employee.java, which implements Serializable interface.
b.   There is a class PermanentEmployee, which extends Employee class.

Your problem statement is, you have to restrict PermanentEmployee objects from serialization process.

Let me give a working example first, after that will see how to solve this problem.


Employee.java
import java.io.Serializable;

public class Employee implements Serializable {
 private static final long serialVersionUID = 1234L;

 private int id;
 private String firstName;
 private String lastName;

 public int getId() {
  return id;
 }

 public void setId(int id) {
  this.id = id;
 }

 public String getFirstName() {
  return firstName;
 }

 public void setFirstName(String firstName) {
  this.firstName = firstName;
 }

 public String getLastName() {
  return lastName;
 }

 public void setLastName(String lastName) {
  this.lastName = lastName;
 }

 @Override
 public String toString() {
  return "Employee [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + "]";
 }

}


PermanentEmployee.java
public class PermanentEmployee extends Employee {
 private static final long serialVersionUID = 1234L;

 private String phoneNum;

 public String getPhoneNum() {
  return phoneNum;
 }

 public void setPhoneNum(String phoneNum) {
  this.phoneNum = phoneNum;
 }

 @Override
 public String toString() {
  return "PermanentEmployee [phoneNum=" + phoneNum + ", getId()=" + getId() + ", getFirstName()=" + getFirstName()
    + ", getLastName()=" + getLastName() + ", toString()=" + super.toString() + ", getClass()=" + getClass()
    + ", hashCode()=" + hashCode() + "]";
 }

}


Test.java

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

public class Test {
 private static ObjectOutputStream out;
 private static ObjectInputStream in;

 private static PermanentEmployee getEmployee() {
  PermanentEmployee emp = new PermanentEmployee();
  emp.setId(1);
  emp.setFirstName("Hari Krishna");
  emp.setLastName("Gurram");
  emp.setPhoneNum("123456");

  return emp;
 }

 public static void main(String args[]) throws IOException, ClassNotFoundException {
  /* Serialize object */
  FileOutputStream fos = new FileOutputStream("ser.out");
  out = new ObjectOutputStream(fos);
  PermanentEmployee emp = getEmployee();
  out.writeObject(emp);

  /* Deserialize object */
  FileInputStream fis = new FileInputStream("ser.out");
  in = new ObjectInputStream(fis);
  PermanentEmployee emp1 = (PermanentEmployee) in.readObject();

  System.out.println(emp1);

 }
}

Output

PermanentEmployee [phoneNum=123456, getId()=1, getFirstName()=Hari Krishna, getLastName()=Gurram, toString()=Employee [id=1, firstName=Hari Krishna, lastName=Gurram], getClass()=class PermanentEmployee, hashCode()=1096979270]

As you see the output, since Employee class is implementing Serializable interface, I can able to serialize all the sub classes (PermanentEmployee) of Employee class.

How to restrict sub class from serialization?
By using custom serialization you can restrict sub class from serialization. In my previous post, I already explained how to achieve custom serialization. To avoid Java serialization you need to implement writeObject() and readObject() method in your Class and need to throw NotSerializableException from those method.

Add following methods to PermanentEmployee class.

private void writeObject(java.io.ObjectOutputStream stream) throws IOException {
         throw new NotSerializableException("PermanentEmployee is not serializable");
}

private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
         throw new NotSerializableException("PermanentEmployee is not serializable");
}

Following is the updated PermanentEmployee.java file.

PermanentEmployee.java

import java.io.IOException;
import java.io.NotSerializableException;
import java.io.ObjectInputStream;

public class PermanentEmployee extends Employee {
 private static final long serialVersionUID = 1234L;

 private String phoneNum;

 public String getPhoneNum() {
  return phoneNum;
 }

 public void setPhoneNum(String phoneNum) {
  this.phoneNum = phoneNum;
 }

 @Override
 public String toString() {
  return "PermanentEmployee [phoneNum=" + phoneNum + ", getId()=" + getId() + ", getFirstName()=" + getFirstName()
    + ", getLastName()=" + getLastName() + ", toString()=" + super.toString() + ", getClass()=" + getClass()
    + ", hashCode()=" + hashCode() + "]";
 }

 private void writeObject(java.io.ObjectOutputStream stream) throws IOException {
  throw new NotSerializableException("PermanentEmployee is not serializable");
 }

 private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
  throw new NotSerializableException("PermanentEmployee is not serializable");

 }

}

Re run Test.java, you can able to see following output.

Exception in thread "main" java.io.NotSerializableException: PermanentEmployee is not serializable
 at PermanentEmployee.writeObject(PermanentEmployee.java:26)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 at java.lang.reflect.Method.invoke(Method.java:498)
 at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:1028)
 at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1496)
 at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
 at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
 at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
 at Test.main(Test.java:26)

You may like






No comments:

Post a Comment