Monday, December 6, 2010

How to make a non-serializable class serializable

I have a class which is not serializable. If i will try to serialize the object of it than i am going to get exception "java.io.NotSerializableException"

And now if this class is not not modifiable/available to modify (may be its a third party), and so we do not have any control.

for e.g following is the non serializable class
class MyNonSerializableClass {
 String str = new String("mystring");
 MyNonSerializableClass(){
  
 }
 MyNonSerializableClass(String s) {
  this.str = s;
 }

 public String getStr() {
  return str;
 }

 public void setStr(String str) {
  this.str = str;
 }

}



In order to serialize the object we can write a wrapper class over MyNonSerializableClass and which is implementing Serializable interface.
And the most important thing, we control the readObject and writeObject methods so that we can decide what need to be written with the wrapper class.

something like this:

class MyNonSerializableClassWrapper extends MyNonSerializableClass implements Serializable {
 MyNonSerializableClassWrapper(){
  super();
 }
 MyNonSerializableClassWrapper(String s) {
  super(s);
 }

 private void writeObject(ObjectOutputStream out) throws IOException {
  // not required the default write object
  // ----> out.defaultWriteObject();
  out.writeObject(super.getStr());
 }

 private void readObject(ObjectInputStream in) throws IOException {
  // not required the default read object
  // ----> in.defaultReadObject();
  try {
   super.setStr((String) in.readObject());
  } catch (ClassNotFoundException e) {
   e.printStackTrace();
  }
 }
}


As the wrapper class itself does not have any properties/attributes so defaultread and write is not required.
By getting the super class value and setting it during the write and read to serialized object we can achieve the serialization and deserialization even if a class is not implementing Serializable interface.


private void WriteObjectToFile() {
try {
  FileOutputStream fo = new FileOutputStream("c:\\test.ser");
  ObjectOutputStream os = new ObjectOutputStream(fo);
  os.writeObject(new MyNonSerializableClassWrapper("This is a test of 
                                           serialization"));
  fo.close();

  } 
  catch (FileNotFoundException e) {
    e.printStackTrace();
  } 
  catch (IOException e) {
    e.printStackTrace();
  }
}


private void ReadObjectFromFile() {
try {
  FileInputStream fi = new FileInputStream("c:\\test.ser");
  ObjectInputStream in = new ObjectInputStream(fi);
  MyNonSerializableClassWrapper mw = (MyNonSerializableClassWrapper) 
  in.readObject();
  fi.close();
  System.out.println("serialized object value is: " + mw.getStr());
  } 
  catch (FileNotFoundException e) {
      e.printStackTrace();
  } 
  catch (IOException e) {
    e.printStackTrace();
  } 
  catch (ClassNotFoundException e) {
    e.printStackTrace();
  }
}




3 comments:

  1. Hi,

    Just to add while writing Serializable class , its good practice to put a Seriazlizable alert in file so that when some one else add a new field in the class he must ensure that field is either transient or Serializable , so that Serializability of class should not break.

    Thanks
    Javin
    Why String is immutable in Java

    ReplyDelete
  2. Good idea but if third party class is final ?
    May be in that case we can have this wrapper class have the same variables as our third party class.
    In the constructor of our wrapper we can take thirdparty object as parameter and set the values in our wrapper class. And we can provide a method in the wrapper to return the object of type thirdparty.

    something like this.

    final class ThirdParty{
    private int field1;
    private int field2;
    }

    public class MyWrapper implments ThirdParty{
    int field1;
    int field2;

    public MyWrapper (ThirdParty tp){
    this.field1 = tp.field1;
    this.field2= tp.field2;
    }

    public ThirdParty getTP(){
    ThirdParty tp = new ThirdParty();
    tp.field1 = this.field1;
    tp.field2 = this.field2;
    return tp;
    }
    }

    ReplyDelete
  3. What happens if the 3-rd party MyNonSerializableClass hasn't a no-arg constructor?

    ReplyDelete