Sunday, December 20, 2009

Serializable

java.io.Serializable



java.lang.Serializable interface is markable interface, which intimates to JVM and ObjectStreamClass that this class possible to persist. All the fields in this class will be persisted while writing into stream using ObjectOutputStream class. Persisted data will be restored using ObjectInputStream



Persisting object is useful in following cases

  • to transmit object state over network

  • to transmit object state to other JVM

  • store and recreate object from the particular state of object




In the folloing program, EmployeeBean object is stored in file '/tmp/a.txt', and using this persistance, EmployeeBean object is recreated and name field value also get restored from file.




import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class ObjectStreamClassTest {

public static class EmployeeBean implements Serializable {
String name;

String designation;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getDesignation() {
return designation;
}

public void setDesignation(String designation) {
this.designation = designation;
}
}

public static void main(String[] args) throws Exception {

ObjectStreamClassTest.EmployeeBean emp = new EmployeeBean();
emp.setName("Krishna");

FileOutputStream bos = new FileOutputStream(new File("/tmp/Employee.txt"));
ObjectOutputStream out = new ObjectOutputStream(bos);
out.writeObject(emp);
out.close();

FileInputStream bis = new FileInputStream(new File("/tmp/Employee.txt"));
ObjectInputStream in = new ObjectInputStream(bis);
EmployeeBean empFromPersist = (EmployeeBean) in.readObject();
System.out.println("Employee name from persisted Bean ::" + empFromPersist.getName());
in.close();

}
}


serialVersionUID


Unique Identifier used to identify the version of the class, which helps to identify the class in which object stream is generated and also instructs JVM to restore Object using the class which has same version UID. The serialVersionUID is computed using the signature of a stream of bytes that reflect the class definition.



serialver tool comes with JSDK, which helps to generate UID.

use: serialver [-classpath classpath] [-show] [classname...]



Serializable implementing class has to have a serialVersionUID field. If this field is not declared explicitly, then JVM will create serialVersionUID in runtime and assign for a class. However, it is strongly recommended that all serializable classes explicitly declare serialVersionUID values. serialVersionUID generation costly for JVM in runtime, and more over, unexpected serialVersionUID may get created.



If serialversionID mismatched, we do get following exception

Exception in thread "main" java.io.InvalidClassException: ObjectStreamClassTest$EmployeeBean; 
local class incompatible: stream classdesc serialVersionUID = 4258520358186173223, local class serialVersionUID = 0
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:562)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1583)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1496)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1732)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)




If Streamed class not found in, target system where strea get read, then ClassNotFoundException will be thrown.


import java.io.File;
import java.io.FileInputStream;
import java.io.ObjectInputStream;

public class ObjectStreamClassTest {

public static void main(String[] args) throws Exception {

FileInputStream bis = new FileInputStream(new File("/tmp/Employee.txt"));
ObjectInputStream in = new ObjectInputStream(bis);
EmployeeBean empFromPersist = (EmployeeBean) in.readObject();
System.out.println("Employee name from persisted Bean ::" + empFromPersist.getName());
in.close();
}
}

If we run above code after '/tmp/Employee.txt' creation using the above sample code. Following exception will be thrown



Exception in thread "main" java.lang.ClassNotFoundException: ObjectStreamClassTest$EmployeeBean
at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
at java.lang.ClassLoader.loadClass(ClassLoader.java:303)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:316)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:247)
at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:604)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1575)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1496)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1732)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:351)
at ObjectStreamClassTest.main(ObjectStreamClassTest.java:47)



Content in Object Stream



What will be stored in Employee.txt?

Content will be organized as documented in Object Serialization Specification, Section 2, Object Output Classes


  1. The class name.
  2. The class modifiers written as a 32-bit integer.
  3. The name of each interface sorted by name.
  4. For each field of the class sorted by field name (except private
    static
    and private transient fields:

    1. The name of the field.
    2. The modifiers of the field written as a 32-bit integer.
    3. The descriptor of the field.

  5. If a class initializer exists, write out the following:

    1. The name of the method, <clinit>.
    2. The modifier of the method, java.lang.reflect.Modifier.STATIC,
      written as a 32-bit integer.
    3. The descriptor of the method, ()V.

  6. For each non-private constructor sorted by method name and signature:

    1. The name of the method, <init>.
    2. The modifiers of the method written as a 32-bit integer.
    3. The descriptor of the method.

  7. For each non-private method sorted by method name and signature:

    1. The name of the method.
    2. The modifiers of the method written as a 32-bit integer.
    3. The descriptor of the method.

  8. The SHA-1 algorithm is executed on the stream of bytes produced by DataOutputStream and produces five 32-bit values sha[0..4].
  9. The hash value is assembled from the first and second 32-bit values of the SHA-1 message digest.
    If the result of the message digest, the five 32-bit words H0 H1 H2 H3 H4, is in an array of five int values named sha, the hash value would be computed as follows:

    long hash = ((sha[0] >>> 24) & 0xFF) |
    ((sha[0] >>> 16) & 0xFF) << 8 |
    ((sha[0] >>> 8) & 0xFF) << 16 |
    ((sha[0] >>> 0) & 0xFF) << 24 |
    ((sha[1] >>> 24) & 0xFF) << 32 |
    ((sha[1] >>> 16) & 0xFF) << 40 |
    ((sha[1] >>> 8) & 0xFF) << 48 |
    ((sha[1] >>> 0) & 0xFF) << 56;






Serializable : Class Hierarchical



If Class implements Serializable then its subclass also serializable. In the below code, if we write EmployeeBean object and retrieve field values for EmployeeBean.


public Organization implements Serializable {
String orgname; ...
}

public class EmployeeBean extends Organization {...}



Though superclass did not implement Serializable, subclass implements Serializable then only the subclass fields are serialized. In the below sample, orgname field will not be serialized.


public Organization {
String orgname; ...
}

public class EmployeeBean extends Organization implements Serializable{... }



Flexibility


While restoring Object state from Stream, following things will not harm restore operation




  1. Class may have +/- in number of methods.

  2. Class may have +/- in number of fields.

  3. Access modifier may get changed for fields and methods.

  4. Order of fields will not be counted.

  5. Implementing interface and superclass also be not counted.

  6. and etc.,



Transient keyword


Some of the Java classes not possible to persist and reuse in target environment. For instance, java.io.File created in machine A and refering path some xYZ, whereas there is no guarantee, that same path is exist in target machine B. In general, java.io packaged classes will not serialized.



In some cases, business mandates that certain fields need not to be serialzed, which has to be prevented in serialization operation. To do this, we have to define the variable with transient keyword.



Field value will not be restored if target machine declares the variable with transient, though Source machine declares particular variable as non-transient variable.


transient String name;

No comments:

Post a Comment

Recent Posts

Unix Commands | List all My Posts

Texts

This blog intended to share the knowledge and contribute to JAVA Community such a way that by providing samples and pointing right documents/webpages. We try to give our knowledege level best and no guarantee can be claimed on truth. Copyright and Terms of Policy refer blogspot.com