Wednesday, November 18, 2009

Java Serialization A Complete Tutorials.

Java Serialization
    In Programming layman’s language Serialization is the process of converting an object into a sequence of bits. That is the sequence of bytes can be persisted on a storage medium like a file or a memory buffer, and it can be transmitted across networks, hence later it can be restored as the same Object by the process of de serialization .ie It is a mechanism with which you can save the state of an object by converting it to a byte stream. This process of serializing an object is also called deflating or marshalling

Object serialization provides the foundation for Java's remote method invocation (RMI) capabilities that enable Java programs that are distributed over a network to invoke each others so-called "remote methods." RMI is used frequently in distributed enterprise applications that are built with Java Enterprise Edition (Java EE).

Let’s check different Scenarios while object serializing.

1.While Serializing an Object it will recursively checks the reference objects whether they are implemented Serializable interface or Not. Means every reference of a Serializing Object should also be Serialized, Otherwise it will generate java.io.NotSerializableException.

        Example:
        class MyDetails implements Serializable{
                String name;
                int age;
        }

Important point about java.lang.Object not implementing the Serializable interface is that any class you create that extends only Object (and no other serializable classes) is not serializable unless you implement the interface yourself.

“The object to be persisted must implement the Serializable interface or inherit that implementation from its object hierarchy.”

2.We did the basic Java Serialization, Now if we need to block some fields should not be saved through Serialization, here it comes with the Java Keyword Transient.

Ex: transient private Integer age=28;
This statement declares an integer variable named age is not a part of the persistent state of the class.

You use the transient keyword to indicate to the Java virtual machine that the indicated variable is not part of the persistent state of the object. In the saving Object Time JVM will discard the transient variables. Variables that are part of the persistent state of an object must be saved when the object is archived.

Scenario Where we Use Transient:
     In system-level classes like Thread, OutputStream and its subclasses, and Socket are not serializable. Indeed, it would not make any sense if they were. For example, thread running in my JVM would be using my system's memory. Persisting it and trying to run it in your JVM would make no sense at all.

          Class MyAnimation{
                  transient Thread serialPortReader.
          }

Here the serial port reading thread will be different in different


3.Stop Serialization:

 In some scenario if we want to stop the serialization, you are thinking how. Lets see an example

          Class Person implements Serialization{
          }
        
          Class Student extends Person{
          }

Here if we need to block Student Object Serialization, How we do?

         Private void writeObject(ObjectOutputStream out) throws IOException
         {
                throw new NotSerializableException("Not today!");
         }

         private void readObject(ObjectInputStream in) throws IOException
         {
                throw new NotSerializableException("Not today!");
         }

Here once you try to serialize the Student Object It will throw NotSerializableException.

4.Versioning Serialization

 One interesting thing will come into our mind that, once we stored the Object and later the Class is being changed, then how you will manage or restore the Object.

In Java 1.1, they have introduced version number. A specific class variable, serialVersionUID (representing the Stream Unique Identifier, or SUID), may be used to specify the earliest version of the class that can be deserialized. The SUID is declared as follows:

          static final long serialVersionUID = 2L;

This particular declaration and assignment specifies that version 2 is as far back as this class can go. It is not compatible with an object written by version 1 of the class, and it cannot write a version 1 object. If it encounters a version 1 object in a stream (such as when restoring from a file), an InvalidClassException will be thrown.

Incase if we are not providing any serialVersionUID the jvm will assign a default while the object is serialized.

The following code will help us to get the SerialVersionId.

          ObjectStreamClass myObject = ObjectStreamClass.lookup(Class.forName( "MyClass" ) );
          long theSUID = myObject.getSerialVersionUID();

Hence we can check the versioned of the object and handle the InvalidClassException on Runtime.
.
Lets look a complete Example :
package serializing;

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

public class Serialize {

          /**
         * @param args
         */
         public static void main(String[] args) {
                 FileOutputStream fileOut = null;
                 ObjectOutputStream out = null;
                 try {
                         fileOut = new FileOutputStream("test.txt");                     
                         out = new ObjectOutputStream(fileOut);
                         CollegeStudent student = new CollegeStudent("WMO","Asker");
                         out.writeObject(student);
                 } catch (Exception e) {
                         // TODO Auto-generated catch block
                         e.printStackTrace();
                 } finally {
                          try {
                                out.close();
                                fileOut.close();
                         } catch (IOException e) {
                         // TODO Auto-generated catch block
                                e.printStackTrace();
                         }
                 }

                 FileInputStream fileIn = null;
                 ObjectInputStream in = null;
                 try {
                        fileIn = new FileInputStream("test.txt");
                        in = new ObjectInputStream(fileIn);
                        CollegeStudent student = (CollegeStudent) in.readObject();
                        System.out.println(student);
                 } catch (Exception e) {
                        e.printStackTrace();
                 } finally {
                        try {
                             out.close(); fileOut.close();
                        } catch (IOException e) {
                             e.printStackTrace();
                        }
                 }
          }
}

class Student  implements Serializable{
        String name;
        public Student(String name) {
              super();
              this.name = name;
        }

        public Student() {
        }
        @Override
        public String toString() {
               return "["+ name + "]";
        }

        public String getName() {
              return name;
        }


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

class CollegeStudent extends Student  {
        String college="";

        public String getCollege() {
              return college;
        }

        public void setCollege(String college) {
              this.college = college;
        }

        public CollegeStudent(String college,String name) {
              super(name);
              this.college=college;
        }
        public CollegeStudent() {
              super("NO VAAL");
        }

        @Override
        public String toString() {
              return "[" + name + ","+college+"]";
        }
}

In the Above Example Lets Discuss the different Scenarios.

 Case 1: Student Class implements Serializable Interface. And College Student Does Not.

          CollegeStudent cs=new CollegeStudent(“College 1”,“Student 1”);
          //Save the Object.

          //Retrieve the Object and Print. The out put will be as Follows.

          [Student 1,College 1]

Case 2: Student Class Does Not. implements Serializable Interface. And CollegeStudent Does.

         CollegeStudent cs=new CollegeStudent(“College 1”,“Student 1”);
         //Save the Object.

         //Retrieve the Object and Print. The out put will be as Follows.

         java.io.InvalidClassException: serializing.CollegeStudent; no valid constructor
         at java.io.ObjectStreamClass.(ObjectStreamClass.java:455)
         at java.io.ObjectStreamClass.lookup(ObjectStreamClass.java:297)
         at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1035)
         at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:302)
         at serializing.Serialize.main(Serialize.java:18)


Case 3: Both the Student and CollegeStudent implements Serializable Interface

If the parent Class Implements the Serializable then it is not required, if provided Not an Issue. It will behave as Case 1:

         CollegeStudent cs=new CollegeStudent(“College 1”,“Student 1”);
         //Save the Object.
         //Retrieve the Object and Print. The out put will be as Follows.
         [Student 1,College 1]


Case 4: Lets make some transient Fields. For example in Student class

         transient String name;

         CollegeStudent cs=new CollegeStudent(“College 1”,“Student 1”);
         //Save the Object.
         //Retrieve the Object and Print. The out put will be as Follows.
         [null,College 1]

Case 5: Lets make some transient Fields. For example in Student class

         transient String college="";
         CollegeStudent cs=new CollegeStudent(“College 1”,“Student 1”);
         //Save the Object.

         //Retrieve the Object and Print. The out put will be as Follows.
         [Student 1,null]

No comments: