Search code examples
javaserializationjava-custom-serialization

simulating java object externalization via custom serialization


The main benefit of externalization over serialization is that externalization persists only part of the object, not the whole object as in case of serialization. But i think that we can simulate externalization via custom serialization if we will not call defaultWriteObject() method of ObjectOutputStream in writeObject() method of the serializable class. So without calliing defaultWriteObject() method and only persisting the needed instance variables of serializable class in writeObject() method we can achieve externalization benefits.

Here is an example demonstrating the aforementioned things:

package com.test;

import java.io.*;

public class Test {
    public static void main(String[] args) throws FileNotFoundException,     IOException, ClassNotFoundException {
        Dog dog = new Dog();
        System.out.println("before serialization: i = " + dog.i + ", j = " +     dog.j);

        FileOutputStream fos = new FileOutputStream("abc.ser");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(dog);

        FileInputStream fis = new FileInputStream("abc.ser");
        ObjectInputStream ois = new ObjectInputStream(fis);
        Dog dog2 = (Dog) ois.readObject();
        System.out.println("after deserialization: i = " + dog2.i + ", j = " +      dog2.j);

    }

    public static class Dog implements Serializable {
        int i = 10;
        int j = 20;

        private void writeObject(ObjectOutputStream oos) throws IOException{
            //oos.defaultWriteObject();
            System.out.println("In WriteObject");
            oos.writeInt(i);
        }

        private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
            //ois.defaultReadObject();
            System.out.println("In ReadObject");
            i = ois.readInt();
        }
    }
}

The output for this code is:

before serialization: i = 10, j = 20
In WriteObject
In ReadObject
after deserialization: i = 10, j = 0

As you can see, the oos.defaultWriteObject() and ois.defaultReadObject(); are commented and we persist and restore only the instance variable i.

So, is my assumption correct that we can simulate externalization concept via custom serialization ?


Solution

  • So, is my assumption correct that we can simulate externalization concept via custom serialization ?

    Your assumption is correct that the programmer has the ability to construct any serialized form for his class that he chooses.

    The Serializable interface is a marker interface that signals to the Java Runtime environment that Java-based serialization has been enabled for the implementing class. If you do nothing else, the Java Runtime invokes the default serialization facility which creates a serialized form for you from all the instance fields of your class.

    The best serialized form for a class is one which:

    • Describes only the logical state of its instances
    • Contains no implementation-specific details or metadata
    • Writes and reads the minimum information required to stream and restore the class instances

    For example, in your code above, if both i and j describe the meaningful state of your objects, then a serialized form which did not include j would be flawed since you would not be able to restore the object to its meaningful state after deserialization.

    However, if i describes meaningful state but j is an implementation detail that is not part of the object's logical state, then it would be a best practice to eliminate j from the stream in order to get a more optimal serialized form.

    While the default serialized form (emitted by the built-in Java serialization facility) is often adequate for simple value classes, more sophisticated abstractions contain metadata and implementation information which should not become part of their serialized forms.

    In order to help programmers design the best serialized form for their classes (if the default form is not adequate), Java provides two broad mechanisms for generating an optimal serialized form for objects:

    • Customized serialization
    • The Externalizable interface

    The former strategy allows the programmer to modify the behavior of the built-in Java serialization facility by using the transient keyword, and hooks into methods such as readObject(), writeObject(), readResolve(), etc. The use of Serialization Proxies is especially recommended for immutable value classes with invariants that must be protected.

    The latter strategy has the programmer implement Externalizable instead of Serializable (Externalizable itself extends Serializable). The Externalizable interface, unlike Serializable, is not a marker interface. Its methods, when implemented, are intended to give the programmer complete control over how an object's serialized form is emitted and restored.

    "The main benefit of externalization over serialization is that externalization persists only part of the object, not the whole object as in case of serialization. "

    A serialized form which contains only "part of an object" and which does not contain all the information necessary to reconstitute the state of an object as it existed before it was serialized is a flawed serialized form. Such a form can be expected to cause problems in those platforms that rely on serialization for inter-process communication.