Tuesday, April 25, 2017

Java Serialization - Part II

We have already discussed the basics of Java Serialization in part I of this article. 

Now let's discuss it deeply and how it works.

First let's start with the serialversionuid.

The serialVersionUID is used as a version control in a Serializable class. 

If you do not explicitly declare a serialVersionUID,  JVM will do it for you automatically, based on various properties of the Serializable class. 

Java's Algorithm of Calculating serialversionuid (Read more details here)
  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;

Java's serialization algorithm

The algorithm to serialize an object is described as below:
  • It writes out the metadata of the class associated with an instance.
  • It recursively writes out the description of the superclass until it finds java.lang.object.
  • Once it finishes writing the metadata information, it then starts with the actual data associated with the instance. But this time, it starts from the topmost superclass.
  • It recursively writes the data associated with the instance, starting from the least superclass to the most-derived class.

Things To Keep In Mind:

1. Static fields in a class cannot be serialized. 

public class A implements Serializable{
     String s;
     static String staticString = "I won't be serializable";
}

2. If the serialversionuid is different in the read class it will throw a Class cast exception.

3. If a class implements serializable then all its sub classes will also be serializable.

public class A implements Serializable {....};

public class B extends A{...} //also Serializable


4. If a class has a reference of another class, all the references must be Serializable otherwise serialization process will not be performed. In such case, NotSerializableException is thrown at runtime.

Eg:

    public class B{
         String s,
         A a; // class A needs to be serializable i.e. it must implement Serializable
    }

No comments:

Post a Comment