Serialization

From Suhrid.net Wiki
Revision as of 00:40, 30 August 2011 by Suhridk (talk | contribs) (→‎Intro)
Jump to navigationJump to search

Intro

  • Mechanism to persist state of objects
  • ObjectOutputStream.writeObject() - serialize and write
  • ObjectInputStream.readObject() - read and deserialize
  • Object and its complete object graph being seralized must implement the Serializable interface.
  • If any object needs to be skipped from the serialization process - mark it as transient.
  • In below example, Thing is not serializable, so when a Thing is used as a field in Majig the field is marked as transient.
class Thing {
	
	private String name;
	
	public Thing(String name) {
		this.name = name;
	}
	
	public void setName(String name) {
		this.name = name;
	}
	
	public String getName() {
		return name;
	}
	
}

class Majig implements Serializable {
	private int id;
	
	private transient Thing t;
	
	public int getID() {
		return id;
	}
	
	Majig(int id, Thing t) {
		this.id = id;
		this.t = t;
	}
}

public class Ser1 {

	public static void main(String[] args) {
		
		Majig m1 = new Majig(1, new Thing("T1"));
		Majig m2 = new Majig(2, new Thing("T2"));
		
		File savFile = new File("majig.sav");
		
		try {
			ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(savFile));
			
			os.writeObject(m1);
			os.writeObject(m2);
			
			System.out.println("Serialized m1 and m2");
			
			os.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}

writeObject and readObject

  • When serialized objects are deserialized, what happens to the transient fields ? They will be null.
  • writeObject and readObject are callback methods that we can define in the code which offer a way to save some part of the object's state manually.
  • This is the contract which must be followed: The methods must be defined in the class which we are trying to serialize.
private void writeObject(ObjectOutputStream os) {
}

private void readObject(ObjectInputStream is) {
}
  • For e.g. in the above case since Thing is transient, we can save Thing's name field instead during serialization and rebuild Thing object using the name during deserialization.
import java.io.*;

class Thing {
	
	private String name;
	
	public Thing(String name) {
		this.name = name;
	}
	
	public void setName(String name) {
		this.name = name;
	}
	
	public String getName() {
		return name;
	}
	
	public String toString() {
		return getName();
	}
	
}

class Majig implements Serializable {
	private int id;
	
	private transient Thing t;
	
	public int getID() {
		return id;
	}
	
	public Thing getThing() {
		return t;
	}
	
	Majig(int id, Thing t) {
		this.id = id;
		this.t = t;
	}
	
	private void writeObject(ObjectOutputStream os) {
		try {
			os.defaultWriteObject();
			os.writeUTF(t.getName());
		} catch (IOException ioe) {
			ioe.printStackTrace();
		}
	}
	
	private void readObject(ObjectInputStream is) {
		try {
			is.defaultReadObject();
			t = new Thing(is.readUTF());
		} catch (Exception ioe) {
			ioe.printStackTrace();
		}
	}
	
}

public class Ser1 {

	public static void main(String[] args) {
		
		Majig m1 = new Majig(1, new Thing("T1"));
		Majig m2 = new Majig(2, new Thing("T2"));
		
		File savFile = new File("majig.sav");
		
		try {
			ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(savFile));
			
			os.writeObject(m1);
			os.writeObject(m2);
			
			System.out.println("Serialized m1 and m2");
			
			os.close();
			
			ObjectInputStream is = new ObjectInputStream(new FileInputStream(savFile));
			
			Majig newm1 = (Majig) is.readObject();
			Majig newm2 = (Majig) is.readObject();
			
			System.out.println("Deserialized m1 and m2");
			
			System.out.println(newm1.getID() + ", " + newm1.getThing());
			System.out.println(newm2.getID() + ", " + newm2.getThing());
			
			is.close();
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}