Quick knowledge test on Java Serialization and Deserialization 



What is serialization? 

To make the object live beyond the lifetime of JVM. 


Name some of the System classes in java which do not implement Serializable? 

Thread, OutputStream and its sub classes, Socket, File 


Can a class having a Thread object reference be persisted? 

Yes just declare the thread object as transient. 


Can the virtual machine call private methods of an object? 

Although one object cannot call the private methods of another object, however virtual machine can call private methods of an object. In object serialization if we override methods readObject, writeObject then even though these methods are declared as private, the JVM will be able to call them. 


Can we stop object serialization? 

We can do it by throwing NotSerializableException (extending IOException) from overridden readObject and writeObject. 


What is the difference between Serializable and Externalizable interfaces?

Externalizable interface gives us more control oven object serialization.  


How do we seal and sign a serialized object?


We can encrypt a serialized data to ensure it isn’t modified afterwards. Although cryptographic encryption can be used in writeObject and readObject, there's still a better way. If we want to encrypt and sign an entire object, we can put it in a javax.crypto.SealedObject and/or java.security.SignedObject wrapper. Both classes are serializable. A symmetric key is required for encryption. It must be managed independently. Similarly, SignedObject can be used for data verification, it also requires a symmetric key, which must be managed independently.

The combination of these two objects allow us to seal and sign serialized data without worrying about the details of digital signature verification or encryption.


public static Serializable decryptAndDeserializeObject(final String string, final SecretKey syKey) {

        if (string == null) {
            throw new IllegalArgumentException(“String is Null…”);
        }

        try {
            final byte[] password = BaseEncoding.base64().decode(string);
            final ByteArrayInputStream bis = new ByteArrayInputStream(password);
            final ObjectInputStream in = new ObjectInputStream(bis);
            final SealedObject pwdSo = (SealedObject) in.readObject();
            return (Serializable) pwdSo.getObject(syKey);
        } catch (final Exception e) {
            e.printStackTrace();
            throw new Exception(e.toString());
        }
    }



What is the importance of closing and resetting the ObjectOutputStreams? 

It holds the reference of the object being written to the stream, any repeated attempt to write the modified object state with the same stream may not be reflected in the bytes persisted. 



Some rules of Java serialization


  • An object is serializable only if its class or its superclass implements Serializable (or Externalizable) interface.
  • Class must be visible at the point of serialization.
  • An object is serializable (class implements Serializable interface) even if its superclass is not, given that the first superclass in the hierarchy of the serializable class, that does not implements Serializable interface, has a no-arg constructor. If this is violated, readObject() will produce a java.io.InvalidClassException at runtime.
  • All primitive types are serializable. 
  • Static fields (with static modifier) are not serialized.
  • Transient fields (with transient modifier) are not serialized, (i.e., not saved or restored). 
  • Class properties which don’t support serialization must be marked as Transient, for example File, OutputStream, Thread, Socket
  • The no-arg constructor of every non-serializable superclass executes when an object is deserialized. A superclass field cannot be serialized if it is not Serializable.
  • Deserialized object’s constructor does not run when it is deserialized.
  • If member variables of a serializable object reference to a non-serializable object, the code will compile but a RuntimeException will be thrown.

What happens when serialVersionUID of the class has changed and object data having the old serialVersionUID is read through deserialization process?


Answer: Deserialization process will throw java.io.InvalidClassException.


java.io.InvalidClassException: serialization.Bean; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2

at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:616)

at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1623)

at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1518)

at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1774)

at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)

at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)

at serialization.BeanSerializerDeSerializer.deSerialize(BeanSerializerDeSerializer.java:61)

at serialization.BeanSerializerDeSerializer.main(BeanSerializerDeSerializer.java:21)


What changes in the original class don’t break deserialization process?


  • Adding a Static field
  • Adding a Transient field
  • Changing access modifier of a field (private to public or vice-versa)
  • Changing access modifier of a method (private to public or vice-versa)
  • Changing class access modifier (from default to public)
  • Deleting a field
  • Static fields are not serialized. Only instance variables are serialized. Hence, adding or removing static fields doesn’t matter. Converting a static field to instance field too doesn’t matter. Such a field will have a null value on deserialization.
  • Changing a field transient to non-transient and vice-versa.


What changes in the original class break deserialization process?


Changing field type (e.g. int to long)


java.io.InvalidClassException: serialization.Bean; incompatible types for field age

at java.io.ObjectStreamClass.matchFields(ObjectStreamClass.java:2299)

at java.io.ObjectStreamClass.getReflector(ObjectStreamClass.java:2193)

at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:669)

at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1623)

at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1518)

at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1774)

at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)

at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)

at serialization.BeanSerializerDeSerializer.deSerialize(BeanSerializerDeSerializer.java:61)

at serialization.BeanSerializerDeSerializer.main(BeanSerializerDeSerializer.java:21)


Changing package hierarchy (e.g. from serialization to serialization.bean)


java.lang.ClassNotFoundException: serialization.Bean

at java.net.URLClassLoader.findClass(URLClassLoader.java:381)

at java.lang.ClassLoader.loadClass(ClassLoader.java:424)

at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)

at java.lang.ClassLoader.loadClass(ClassLoader.java:357)

at java.lang.Class.forName0(Native Method)

at java.lang.Class.forName(Class.java:348)

at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:626)

at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1613)

at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1518)

at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1774)

at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)

at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)

at serialization.BeanSerializerDeSerializer.deSerialize(BeanSerializerDeSerializer.java:63)

at serialization.BeanSerializerDeSerializer.main(BeanSerializerDeSerializer.java:23)

Comments