Difference between revisions of "Serialization"

From Suhrid.net Wiki
Jump to navigationJump to search
 
(3 intermediate revisions by the same user not shown)
Line 70: Line 70:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 +
== 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.
 +
 +
<syntaxhighlight lang="java5">
 +
 +
private void writeObject(ObjectOutputStream os) {
 +
}
 +
 +
private void readObject(ObjectInputStream is) {
 +
}
 +
 +
</syntaxhighlight>
 +
 +
* 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.
 +
* Before we save/retrieve our custom field, os.defaultWriteObject() and defaultReadObject() must be called to handle the normal serialization process.
 +
 +
<syntaxhighlight lang="java5">
 +
 +
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();
 +
}
 +
}
 +
 +
}
 +
 +
</syntaxhighlight>
 +
 +
 +
== Inheritance and Serialization ==
 +
 +
* During deser, constructor does not run and instance initializers are not run.
 +
* However every non-serializable superclass's constructor will run !
 +
* So a non-serializable superclass constructor can overrwrite an instance variable's value if it runs!
 +
 +
<syntaxhighlight lang="java5">
 +
 +
import java.io.*;
 +
 +
class Gadget {
 +
 +
int val = 10;
 +
 +
protected int getVal() {
 +
return val;
 +
}
 +
 +
protected void setVal(int val) {
 +
this.val = val;
 +
}
 +
 +
Gadget() {
 +
System.out.println("Gadget Constructor");
 +
}
 +
}
 +
 +
class Phone extends Gadget implements Serializable {
 +
 +
Phone() {
 +
System.out.println("Phone Constructor");
 +
}
 +
 +
}
 +
 +
public class Ser2 {
 +
 +
public static void main(String[] args) {
 +
 +
try {
 +
 +
File savFile = new File("phone.sav");
 +
ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(savFile));
 +
Phone op = new Phone();
 +
op.setVal(30);
 +
os.writeObject(op);
 +
System.out.println("Serialized Phone with val :" + op.getVal());
 +
os.close();
 +
 +
ObjectInputStream is = new ObjectInputStream(new FileInputStream(savFile));
 +
Phone p = (Phone) is.readObject();
 +
System.out.println("Deserialized Phone");
 +
System.out.println("Phone Val : " + p.getVal());
 +
is.close();
 +
 +
} catch (Exception e) {
 +
e.printStackTrace();
 +
}
 +
 +
}
 +
 +
}
 +
 +
/*
 +
 +
Output : Note Phone Constructor does not run during deser, but Gadget does thus overrwriting val
 +
 +
Gadget Constructor
 +
Phone Constructor
 +
Serialized Phone with val :30
 +
Gadget Constructor
 +
Deserialized Phone
 +
Phone Val : 10
 +
 +
*/
 +
 +
 +
</syntaxhighlight>
  
 
[[Category:OCPJP]]
 
[[Category:OCPJP]]

Latest revision as of 01:00, 30 August 2011

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.
  • Before we save/retrieve our custom field, os.defaultWriteObject() and defaultReadObject() must be called to handle the normal serialization process.
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();
		}
	}

}


Inheritance and Serialization

  • During deser, constructor does not run and instance initializers are not run.
  • However every non-serializable superclass's constructor will run !
  • So a non-serializable superclass constructor can overrwrite an instance variable's value if it runs!
import java.io.*;

class Gadget {
	
	int val = 10;
	
	protected int getVal() {
		return val;
	}
	
	protected void setVal(int val) {
		this.val = val;
	}
	
	Gadget() {
		System.out.println("Gadget Constructor");
	}
}

class Phone extends Gadget implements Serializable {
	
	Phone() {
		System.out.println("Phone Constructor");
	}
	
}

public class Ser2 {

	public static void main(String[] args) {
		
		try {
			
			File savFile = new File("phone.sav");
			ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(savFile));
			Phone op = new Phone();
			op.setVal(30);
			os.writeObject(op);
			System.out.println("Serialized Phone with val :" + op.getVal());
			os.close();
			
			ObjectInputStream is = new ObjectInputStream(new FileInputStream(savFile));
			Phone p = (Phone) is.readObject();
			System.out.println("Deserialized Phone");
			System.out.println("Phone Val : " + p.getVal());
			is.close();
			
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

}

/*

Output : Note Phone Constructor does not run during deser, but Gadget does thus overrwriting val

Gadget Constructor
Phone Constructor
Serialized Phone with val :30
Gadget Constructor
Deserialized Phone
Phone Val : 10

*/