Serialization and Constructor Invocations

- Gaurav
Don't be shellfish...Google+FacebookTwitterLinkedInRedditDiggtumblrPinterest

java-duke-logo

Serialization and Constructor Invocations

I heard some very strange things about serialization lately and decided to run some test to verify them. I first created a sample class that implements Serializable.

public class ReflectSuper implements Serializable {
    private static final long serialVersionUID = -5030660584919911834L;
    ReflectSuper() {
        System.out.println("SuperConstructor");
    }
}

The line 4 here, ensures that ‘SuperConstructor’ gets printed on my console whenever the constructor is invoked.


The first weird thing, I was told about was,

1. When deserializing, the constructor of the target class is never invoked.

For an average innocent bloke like me, that is a shocker. If the constructor isn’t invoked? Then what goes into creating the object? But, no matter how strange a fact, it is true. I serialized and deserialized a new object expecting that the constructor will be invoked twice.

  • While creating a new object. (Line 4 in code below)
  • While deserializing the serialized object. (Line 14 in code below)
public class Reflect {
    public static void main(String[] args) throws Exception {
        // Created a new object of ReflectSuper to be serialized
	ReflectSuper sub = new ReflectSuper();

	// serialize
	System.out.println("Writing");
	ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("F:\\Test\\Test.serl"));
	os.writeObject(sub);

	// deserialize
	System.out.println("Reading");
	ObjectInputStream is = new ObjectInputStream(new FileInputStream("F:\\Test\\Test.serl"));
	is.readObject();
    }
}

Output

SuperConstructor
Writing
Reading

Explanation
Please note that ‘SuperConstructor’ got printed just once, i.e. only once was the constructor called. It was only when creating the new object explicitly at line 4, constructor was called. Deserialization never invoked the constructor. So, that proves it. But if the constructor is not invoked, what is?


2. Target class should have access to the no-arg constructor of its first non-serializable superclass

If the constructor was not being invoked, why is there need for accessing the no-arg constructor of the first non-serializable super class?

Consider the example below where three classes have been used.

  1. Reflect.java- The main class for performing serialization and deserialization.
  2. ReflectSuper.java- Non serializable super class with a no-args constructor.
  3. ReflectSub.java- Target class which has to be serialized.
// ReflectSuper.java
public class ReflectSuper {
    ReflectSuper() {
        System.out.println("SuperConstructor");
    }
}
// ReflectSub.java
class ReflectSub extends ReflectSuper implements Serializable {
    private static final long serialVersionUID = -5030660584919911834L;

    ReflectSub() {
	System.out.println("SubConstructor");
    }
}
// Reflect.java
public class Reflect {
    public static void main(String[] args) throws Exception {
 	// Created a new object of ReflectSuper to be serialized
	ReflectSub sub = new ReflectSub();

	// serialize
	System.out.println("Writing");
	ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("F:\\Test\\Test.serl"));
	os.writeObject(sub);

	// deserialize
	System.out.println("Reading");
	ObjectInputStream is = new ObjectInputStream(new FileInputStream("F:\\Test\\Test.serl"));
	is.readObject();
    }
}

Output

SuperConstructor
SubConstructor
Writing
Reading
SuperConstructor

Explanation
SuperConstructor is printed twice, this means that the super constructor, i.e. the constructor of the first non-serializable super class is invoked when deserializing.

Serialization works by chaining up each class in the inheritance hierarchy and then saving the state of each superclass until the first non-serialization class is reached. Since, the state of this non-serializable superclass is neither stored and thus never fetched, its constructor has to be invoked while deserializing.



But, all this still doesn’t make sense. Right?

3. If the target class’ constructor is never invoked, then what is used?

Enough with the build up and mystery. Reflection in java has a ReflectionFactory which has a public method newConstructorForSerialization. This method is actually responsible for creating an instance of an object without even invoking the constructor. So, deserialization uses a method very similar to –

/**
 * Returns an instance of a class without invoking it constructor
 *
 * @param clazz
 * @return instance of clazz
 * @throws IllegalArgumentException
 * @throws InstantiationException
 * @throws IllegalAccessException
 * @throws InvocationTargetException
 * @throws SecurityException
 * @throws NoSuchMethodException
 */
public static Object create(Class clazz) throws IllegalArgumentException, InstantiationException,
			IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException {
    ReflectionFactory rf = ReflectionFactory.getReflectionFactory();
    Constructor intConstr = rf.newConstructorForSerialization(clazz, Object.class.getDeclaredConstructor());
    return clazz.cast(intConstr.newInstance());
}

//Usage
ReflectSuper reflectSuper = (ReflectSuper) create(ReflectSuper.class);

Explanation
We notice here, that the create method doesn’t rely on the no-arg constructor of the first non-serializable superclass. So, why does deserialization requires it?

It is actually the way deserialization is designed. It needs the constructor to fill in the default information for the non-serializable part of the object instance. (As discussed in point 2)Cartoon-Devil

Concern
We saw that we don’t really need a constructor to get an instance of a class. Since, we have come this far, lets image a singleton class which is supposed to have only a single instance. But, our little friend here, newConstructorForSerialization thinks otherwise and will help us create more than one instance of the Singleton class here. So, whats the plan to save the earth from this devil which could hack into any singleton class?

Don't be shellfish...Google+FacebookTwitterLinkedInRedditDiggtumblrPinterest