Application Development, Product to Market
  • Home
  • Notes
  • Projects
  • Resources
    • Discovery Log
    • Books I Read
    • Blogs I Visit
    • Tools I Use
  • Home
  • Notes
  • Projects
  • Resources
    • Discovery Log
    • Books I Read
    • Blogs I Visit
    • Tools I Use

Java Serialization

7/1/2013

0 Comments

 
Java Serialization is a mechanism to transform a graph of Java objects into byte stream (an array of bytes) for storage or transmission, such that said array of bytes can be later transformed back into a graph of Java objects.

To opt a class in for Seriliazation, you 

  1. implements Serializable interface, and
  2. use ObjectInputStream/ObjectOutputStream classes, and
  3. declare serialVersionUID (strongly recommended)
package com.test;
import java.io.Serializable;

public class Person implements Serializable{  
  private static final long serialVersionUID = 1L;

  private String firstName;

  private String lastName;
  private Person spouse;

  public Person(String firstName, String lastName){
        this.firstName = firstName; this.lastName = lastName;
  }

  public String getFirstName() { return firstName; }
  public String getLastName() { return lastName; }
  public Person getSpouse() { return spouse; }

  public void setFirstName(String value) { firstName = value; }
  public void setLastName(String value) { lastName = value; }
  public void setSpouse(Person value) { spouse = value; }
}
To serialize the above serializable class to disk:
try{
  Person mark = new Person("Mark", "Zuckerberg");
  Person priscilla = new Person("Priscilla", "Chan");
  mark.setSpouse(priscilla); priscilla.setSpouse(mark);

  FileOutputStream fos = new FileOutputStream("temp.ser"); // 1
  ObjectOutputStream oos = new ObjectOutputStream(fos);
  oos.writeObject(mark);

  oos.writeObject(priscilla);
  oos.close();
}
catch(Exception e){
  ...
}
[1] Serialized data file is usually named with .ser extension.

To deserialize from the disk,
try{
  FileInputStream fis = new FileInputStream("temp.ser");
  ObjectInputStream ois = new ObjectInputStream(fis);
  Person mark = (Person) ois.readObject();

  Person priscilla = (Person) ois.readObject();
  ois.close();

  new File("temp.ser").delete();   // Clean up the file
}
catch (Exception ex){
  ...
}
During deserialization, the fields of non-serializable classes will be initialized by their no-arg constructor of the corresponding non-serializable class. The fields of serializable subclasses will not be initialized by subclasses' constructors, but will be restored from the stream.

serialVersionUID

According to the Serializable Javadoc, to convince the Java runtime that Person on the disk and Person in memory are in fact compatible in term of serialization and deserialization, Java uses a calculated hash based on just about everything of a given class — method names, field names, field types, access modifiers — and compares that hash value against the hash value in the serialized stream. They must have the same serialization version hash (stored as the private static final serialVersionUID field) to be deserialized.

Authough serialVersionUID will be automatically generated if not supplied in the code, it is strongly recommended that all serializable classes explicitly declare serialVersionUID values, since the default serialVersionUID computation may vary depending on compiler implementations, and can thus result in unexpected InvalidClassExceptions during deserialization. There are three options to assign serialVersionUID:

#1: any value you want
private static final long serialVersionUID = 1L;
#2: serialver command

JDK has a build in command called “serialver” to generate the serialVersionUID. If a Serializable class already has a serialVersionUID, serialver will simply report that serialVersionUID to the developer. If not, you cd to the class directory of the serializable class and use “serialver” to generate/suggest a serialVersionUID to be used toward Person class:
% serialver com.test.Person
#3: If you're using Eclipse, simply mouse over the serialization class and you'll get the help from Eclipse.

adding fields to serializable class

It is said that under the following circumstances, adding field to an existing serializable class, the serialization and deserialization compability still works, as long as the serialVersionUID is the same before and after:

  • Adding new fields to a class
  • Changing the fields from static to nonstatic
  • Changing the fields from transient (that marks a member variable not to be serialized when it is persisted to streams of bytes) to non-transient.

customize serialization process

Classes that require special handling during the serialization and deserialization process must implement special methods with these exact signatures:
private void writeObject(java.io.ObjectOutputStream out) throws IOException

private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException;
If it is declared, they will be called from the ObjectOutputStream or ObjectInputStream instead of the default serialization or deserialization process. Please refer to "What are writeObject and readObject" for an example.

security

If you need to encrypt and sign an entire object, the simplest thing is to put it in a javax.crypto.SealedObject and/or java.security.SignedObject wrapper.

proxy

When you serialize a class, transient fields won't be serialized. Sometimes, you want to actually serialize using another slim-down proxy class (e.g. PersonProxy) that only serialize partial core elements of the data. In reverse, when deserializing, you'd like to return to the original class. Entering the concept of proxy. To allow this, there are methods to be implemented.

Serializable classes that need to designate an alternative object to be used when writing an object to the stream should implement these special methods in the original non-proxy class (e.g. Person) with the exact signature:
ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException;
Classes that need to designate a replacement when an instance of it is read from the stream should implement this special method in the proxy class (e.g. PersonProxy) with the exact signature.
ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;
For example,
class PersonProxy implements Serializable{
  public String data;

  public PersonProxy(Person orig)
  {
    data = orig.getFirstName() + "," + orig.getLastName();
    if (orig.getSpouse() != null)
    {
      Person spouse = orig.getSpouse();
      data = data + "," + spouse.getFirstName() + "," + spouse.getLastName();
    }
  }

  private Object readResolve() throws ObjectStreamException
  {
    String[] pieces = data.split(",");
    Person person = new Person(pieces[0], pieces[1]);
    if (pieces.length > 2){
      result.setSpouse(new Person(pieces[2], pieces[3]);
      result.getSpouse().setSpouse(result);
    }
    return person;
  }
}


public class Person implements Serializable{

  private static final long serialVersionUID = 1L;

  private String firstName;
  private String lastName;
  private Person spouse;

  public Person(String firstName, String lastName){
    this.firstName = firstName; this.lastName = lastName;
  }

  public String getFirstName() { return firstName; }
  public String getLastName() { return lastName; }
  public Person getSpouse() { return spouse; }

  public void setFirstName(String value) { firstName = value; }
  public void setLastName(String value) { lastName = value; }
  public void setSpouse(Person value) { spouse = value; }

  private Object writeReplace() throws ObjectStreamException{
    return new PersonProxy(this);
  }

}

references

  • 5 things you didn't know about ... Java Object Serialization
  • Signed and sealed objects deliver secure serialized content
  • Interface Serializable Javadoc
  • What are writeObject() and readObject()?

0 Comments



Leave a Reply.

    Categories

    All
    Algorithm
    Concurrency
    CQ
    Data Structure
    Design Pattern
    Developer Tool
    Dynamic Programming
    Entrepreneur
    Functional Programming
    IDE
    Java
    JMX
    Marketing
    Marklogic
    Memory
    OSGI
    Performance
    Product
    Product Management
    Security
    Services
    Sling
    Social Media Programming
    Software Development

    Feed Widget

    Archives

    May 2020
    March 2020
    April 2018
    March 2018
    February 2018
    December 2017
    March 2017
    November 2016
    June 2016
    May 2016
    April 2016
    October 2015
    September 2015
    August 2015
    September 2014
    July 2014
    June 2014
    May 2014
    March 2014
    January 2014
    December 2013
    November 2013
    October 2013
    September 2013
    August 2013
    July 2013
    June 2013

    RSS Feed

in loving memory of my mother  and my 4th aunt
Photos used under Creative Commons from net_efekt, schani, visnup, Dan Zen, gadl, bobbigmac, Susana López-Urrutia, jwalsh, Philippe Put, michael pollak, oskay, Creative Tools, Violentz, Kyknoord, mobilyazilar