JavaObject-oriented programmingSerialization

Custom serialization

The Java platform specifies a default way by which serializable objects are serialized. The default serialized form is a close representation of physical object structure and therefore should be assumed in cases when physical structure of the object is close to its logical structure. The following snippet illustrates the case:


public class Point implements Serializable {
    /**
    @serial
    */
    private final int x;
    
    /**
    @serial
    */
    private final int y;
    // ...
}

The @serial Javadoc tags will be discussed in following steps.

In cases when a logical structure of the objects substantially differs from the physical one the default serialization form may lead to the number of disadvantages:
  • Physical structure of the object is exported as an API and therefore couldn't be changed in the future
  • Extra memory consumption
  • Extra time consumption during serialization / deserialization
  • Stack overflown caused by recursive traversals of the graph object

The one could easily exclude instance fields from Serialization by marking them transient:

public class SomeClass implements Serializable {
    private int willSerialize;
    private transient int willNotSerialize;
}

If the field is not a part of an object logical structure it's recommended to make it transient. Transient fields are initialized to their default values during object deserialization.

Serializable Java class can define its own way of serializing objects of that class by providing implementations of the following methods:

 private void writeObject(java.io.ObjectOutputStream out) throws IOException;
 private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException;

During custom object reading / writing it's highly suggested to call defaultReadObject and defaultWriteObject methods
  • These methods effectively deal with instance non-transient fields serialization / deserialization
  • The use of these methods allows adding non-transient fields in the future releases with no extra efforts to implement serialization

See the code below for example:

import java.io.IOException;
import java.io.Serializable;

class CustomSerialization implements Serializable {
  
  private static final long serialVersionUID = 1L;
  
  private final int a;
  private final int b;
  
  public CustomSerialization(int a, int b) {
    this.a = a;
    this.b = b;
  }

  // Will mimic default behavior i.e. serialize a and b fields
  private void writeObject(java.io.ObjectOutputStream out) throws IOException {
    out.defaultWriteObject();
  }
  
  // Will mimic default behavior i.e. deserialize a and b fields
  private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
    in.defaultReadObject();
  }
  
}

readObject method implementation should not be restricted to the cases of custom objects deserialization. Since deserialization is an extralinguistic way of object creation, default deserialization protocol can produce objects escaping class invariants. To avoid this, readObject method could be provided to ensure invariants and security. The @serial tag should be placed in the javadoc comment for a default serializable field. The syntax is as follows: @serial field-description The optional field-description describes the meaning of the field and its acceptable values.

@serial

The field-description for @serial provides serialization-specific documentation and is appended to the javadoc comment for the field within the serialized form documentation.
How did you like the theory?
Report a typo