Wednesday, 26 April 2017

Reading all files in a folder - Java Program

This post is about how to read all the files in a directory. Suppose you have folder with files in it and there are sub-folders with files in those sub-folders and you want to read or list all the files.

Here is a folder structure used in this post to read the files. Test, Test1 and Test2 are directories here and then you have files with in those directories.

Test
  abc.txt
  Test1
  test.txt
  test1.txt
 Test2
  xyz.txt

Example Code

There are two ways to list all the files one is using the listFiles() method of the File class which is there in Java from 1.2.

Another way is using Files.walk() method which is a recent addition in Java 8.

 
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Stream;

public class ListFiles {
    public static void main(String[] args) {
      File folder = new File("G:\\Test");
      ListFiles listFiles = new ListFiles();
      System.out.println("reading files before Java8 - Using listFiles() method");
      listFiles.listAllFiles(folder);
      System.out.println("-------------------------------------------------");
      System.out.println("reading files Java8 - Using Files.walk() method");
      listFiles.listAllFiles("G:\\Test");

     }
         
     public void listAllFiles(File folder){
         System.out.println("In listAllfiles(File) method");
         File[] fileNames = folder.listFiles();
         for(File file : fileNames){
             // if directory call the same method again
             if(file.isDirectory()){
                 listAllFiles(file);
             }else{
                 try {
                     readContent(file);
                 } catch (IOException e) {
                     // TODO Auto-generated catch block
                     e.printStackTrace();
                 }
        
             }
         }
     }
         
     public void listAllFiles(String path){
         System.out.println("In listAllfiles(String path) method");
         try(Stream<Path> paths = Files.walk(Paths.get(path))) {
             paths.forEach(filePath -> {
                 if (Files.isRegularFile(filePath)) {
                     try {
                         readContent(filePath);
                     } catch (Exception e) {
                         // TODO Auto-generated catch block
                         e.printStackTrace();
                     }
                 }
             });
         } catch (IOException e) {
             // TODO Auto-generated catch block
             e.printStackTrace();
         } 
     }
     
     public void readContent(File file) throws IOException{
         System.out.println("read file " + file.getCanonicalPath() );
         try(BufferedReader br  = new BufferedReader(new FileReader(file))){
               String strLine;
               // Read lines from the file, returns null when end of stream 
               // is reached
               while((strLine = br.readLine()) != null){
                System.out.println("Line is - " + strLine);
               }
              }
     }
     
     public void readContent(Path filePath) throws IOException{
         System.out.println("read file " + filePath);
         List<String> fileList = Files.readAllLines(filePath);
         System.out.println("" + fileList);
     }
     
}

Output

reading files before Java8 - Using listFiles() method
In listAllfiles(File) method
read file G:\Test\abc.txt
Line is - This file is in Test folder.
In listAllfiles(File) method
read file G:\Test\Test1\test.txt
Line is - This file test is under Test1 folder.
read file G:\Test\Test1\test1.txt
Line is - This file test1 is under Test1 folder.
In listAllfiles(File) method
read file G:\Test\Test2\xyz.txt
Line is - This file xyz is under Test2 folder.
-------------------------------------------------
reading files Java8 - Using Files.walk() method
In listAllfiles(String path) method
read file G:\Test\abc.txt
[This file is in Test folder.]
read file G:\Test\Test1\test.txt
[This file test is under Test1 folder.]
read file G:\Test\Test1\test1.txt
[This file test1 is under Test1 folder.]
read file G:\Test\Test2\xyz.txt
[This file xyz is under Test2 folder.]

Here we have two overloaded methods listAllFiles(). First one take File instance as argument that one is used to read files using the File.listFiles() method. In that method while going through the list of files under a folder you check if the next element of the list is a file or a folder. If it is a folder then you recursively call the listAllFiles() method with that folder name. If it is a file you call the readContent() method to read the file using BufferedReader.

Another version of listAllFiles() method takes String as argument. In this method whole folder tree is traversed using the Files.walk() method. Here again you verify if it is a regular file then you call the readContent() method to read the file.

Note that readContent() method is also overloaded one takes File instance as argument and another Path instance as argument.

That's all for this topic Reading all files in a folder - Java Program. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Writing file in Java
  2. How to append to a file in Java
  3. How to read file from the last line in Java
  4. How to find last modified date of a file in Java
  5. Unzipping files in Java

You may also like -

>>>Go to Java Programs page

Monday, 24 April 2017

Object cloning in java

In Java if you assign an object variable to another variable the reference is copied which means both variable will share the same reference. In this case any change in one object variable will be reflected in another.

As example – If there is a class Test and you create an object of that class and then assign that reference to another object variable.

Test obj1 = new Test();
Test obj2 = obj1;

Here both obj1 and obj2 will have the same reference.

Object cloning

What is the option then if you want to quickly create an object using the existing object in such a way that you get a new instance (reference is not shared) with the same content for the fields in the new object as in existing object.

That’s when you can use clone() method which creates an exact copy of the existing object. Then you can modify the cloned object without those modification reflecting in original object (Well we’ll go into shallow copy and deep copy a little later).

clone() method

clone() method is defined as protected in the Object class which you must override as public in any derived classes that you want to clone.

Signature of clone method in Object class

protected native Object clone() throws CloneNotSupportedException;

Process of cloning

There are two required steps if you want to clone any object.

  1. You need to call clone() method of the Object class or provide your own implementation by overriding the clone() method in your class.
  2. Your class, whose object you want to clone, must implement Cloneable interface which is part of java.lang package. Not implementing Cloneable interface will result in CloneNotSupportedException exception being thrown when clone method is called.

Here note that Cloneable interface is a marker interface and defines no members of its own.

Scenario 1- Calling clone() method from a method

Here we have a class Test which implements Cloneable interface and it has a method cloneIt() which calls the clone() method of the Object class.

Class Test

public class Test implements Cloneable{
  int a;
  float f;
 
 Test cloneIt(){
  Test test = null;
  try {
   // Calling clone() method of Object class
   test = (Test)super.clone();
  } catch (CloneNotSupportedException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  return test;
  
 }
}

CloningDemo class

public class CloningDemo {

 public static void main(String[] args) {
  Test t1 = new Test();
  t1.a = 10;
  t1.f = 13.4F;
  // Calling method to clone
  Test t2 = t1.cloneIt();
  System.out.println("t1.a " + t1.a + " t1.f " + t1.f);
  
  System.out.println("t2.a " + t2.a + "t2.f " + t2.f);

  if(t1 != t2){
   System.out.println("Different instances");
  }else{
   System.out.println("Same instances");
  }
 }

}

Output

t1.a 10 t1.f 13.4
t2.a 10t2.f 13.4
Different instances

Here you can see that Test class object t1 is cloned and a new instance t2 is created, in the code even reference equality is checked and you can see that the reference is not shared and both are indeed different instances.

Points to note

Some of the points to note from this code –

  1. Class whose object has to be cloned should implement Cloneable interface, otherwise java.lang.CloneNotSupportedException exception will be thrown.
  2. clone() method is a protected method in Object class, since all the classes inherit from Object class so you can call the protected method of the super class.
  3. While cloning bitwise copy of the object is created.

Scenario 2 – Overriding clone method

Another way to provide clone functionality is to override the clone() method in the class in that case it has to be a public method in order to be accessible.

If we change the classes used in the above example to have overridden clone method and calling that clone method then the ' structure will be as follows –

Test class

public class Test implements Cloneable{
 int a;
 float f;
 // Override clone method
 public Object clone(){
  Object obj = null;
  try {
   // Calling clone() method of Object class
   obj = super.clone();
   } catch(CloneNotSupportedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
  }
  return obj;
 }
}

CloningDemo class

public class CloningDemo {

 public static void main(String[] args) {
  Test t1 = new Test();
  t1.a = 10;
  t1.f = 13.4F;
  // Call clone method
  Test t2 = (Test)t1.clone();
  System.out.println("t1.a " + t1.a + " t1.f " + t1.f);
  
  System.out.println("t2.a " + t2.a + " t2.f " + t2.f);
  
  if(t1 != t2){
   System.out.println("Different instances");
  }else{
   System.out.println("Same instances");
  }
 }
}

Output

t1.a 10 t1.f 13.4
t2.a 10 t2.f 13.4
Different instances

Advantages of cloning

If you have an object, creation of which using the usual way is costly; as example if you have to call DB in order to get data to create and initialize your object. In that scenario rather than hitting DB every time to create your object you can cache it, clone it when object is needed and update it in DB only when needed.

Actually there is a design pattern called prototype design pattern which suggests the same approach.

Shallow copy

In the above examples only primitive types are used so there is no problem, if you change any primitive value that won’t reflect in other object.

What if there is another object reference in your class? As already mentioned when you clone an object all the values for the fields are copied to the cloned object. Since Java is pass by value, if the field value is a reference to an object (a memory address) it copies that reference to the field of the cloned object. In that case referenced field is shared between both objects and any change made to the referenced field will be reflected in the other object too.

This process of cloning when the field values are copied to the new object is known as shallow copy. Shallow copies are simple to implement and typically cheap, as they can be usually implemented by simply copying the bits exactly.

Example code

Let’s try to clarify it with an example. Here we have a Class called ClassA with 2 int fields. Another class ClassB which has a ClassA object and an int field.

Then you create an object objB of ClassB and then clone it to get a new object objB2. In both of these objects reference of ClassA object will be shared.

ClassA

public class ClassA {
 private int i;
 private int j;
 // Constructor
 public ClassA(int i, int j){
  this.i = i;
  this.j = j;
 }
 public void setI(int i) {
  this.i = i;
 }
 public void setJ(int j) {
  this.j = j;
 }
 public int getI() {
  return i;
 }
 public int getJ() {
  return j;
 }
}

ClassB

public class ClassB implements Cloneable{
 private int x;
 private ClassA objA;
 
 public ClassB(int x, ClassA objA){
  this.x = x;
  this.objA = objA;
 }
 public Object clone() throws CloneNotSupportedException{
  return super.clone();
 }
 public int getX() {
  return x;
 }
 public ClassA getObjA() {
  return objA;
 }
 public void setX(int x) {
  this.x = x;
 }
 public void setObjA(ClassA objA) {
  this.objA = objA;
 }
}

CloningDemo class

public class CloningDemo {

 public static void main(String[] args) {
  ClassB objB = new ClassB(10, new ClassA(20, 30));
  
  ClassB objB2 = null;
  try {
   objB2 = (ClassB)objB.clone();
   
  } catch (CloneNotSupportedException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  // value of field i of objA changed 
  // in cloned object
  objB2.getObjA().setI(100); 
  // Value of primitive field x changed 
  // in cloned object
  objB2.setX(1);
  System.out.println("objB.x- " +  objB.getX() + " objB.objA.i- " + objB.getObjA().getI() + " objB.objA.j- " + objB.getObjA().getJ());
  System.out.println("objB2.x- " +  objB2.getX() + " objB2.objA.i- " + objB2.getObjA().getI() + " objB2.objA.j- " + objB2.getObjA().getJ());

 }
}

Output

objB.x- 10 objB.objA.i- 100 objB.objA.j- 30
objB2.x- 1 objB2.objA.i- 100 objB2.objA.j- 30 

In CloningDemo class objB is cloned to get a new instance objB2. Value of primitive field x is changed in the cloned object objB2, you can see that both objects have their own independent values for field x.

Coming to object field, objB2 will have its own field objA where value of field i is changed. You can see that value in the original object objB for objA.i is also changed as the objA reference is shared between the objects. That’s one drawback of shallow copy.

Deep Copy

If you don’t want references of object being copied during the cloning process then option is deep copy. When a deep copy is done objects referenced by the cloned object are distinct from those referenced by original object, and independent.

Deep copies are more expensive, as you need to create additional objects, and can be substantially more complicated, due to references possibly forming a complicated graph.

Example Code

public class ClassB implements Cloneable{
 private int x;
 private ClassA objA;
 
 public ClassB(int x, ClassA objA){
  this.x = x;
  this.objA = objA;
 }
 public Object clone() throws CloneNotSupportedException{
  // Cloning object
  ClassB objB = (ClassB)super.clone();
  // Explicitly assigning reference to new ClassA object
  objB.setObjA(new ClassA(100, objA.getJ()));
  return objB;
 }
 public int getX() {
  return x;
 }
 public ClassA getObjA() {
  return objA;
 }
 public void setX(int x) {
  this.x = x;
 }
 public void setObjA(ClassA objA) {
  this.objA = objA;
 }
}

Here ClassB is changed to create a deep copy while cloning the object. Notice in the clone method, for the cloned object a new ClassA object is created with a new value(100) for field i and keeping the old value for field j. Since it’s a new object so reference is not shared with the classA object of the original object.

If we run this code now using the below program -

public class CloningDemo {

 public static void main(String[] args) {
  ClassB objB = new ClassB(10, new ClassA(20, 30));
  
  ClassB objB2 = null;
  try {
   objB2 = (ClassB)objB.clone();
   
  } catch (CloneNotSupportedException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  // value of field i of objA changed 
  // in cloned object
  //objB2.getObjA().setI(100); 
  // Value of primitive field x changed 
  // in cloned object
  objB2.setX(1);
  System.out.println("objB.x- " +  objB.getX() + " objB.objA.i- " + objB.getObjA().getI() 
     + " objB.objA.j- " + objB.getObjA().getJ());
  System.out.println("objB2.x- " +  objB2.getX() + " objB2.objA.i- " + objB2.getObjA().getI() 
    + " objB2.objA.j- " + objB2.getObjA().getJ());

 }

}

Output

objB.x- 10 objB.objA.i- 20 objB.objA.j- 30
objB2.x- 1 objB2.objA.i- 100 objB2.objA.j- 30

Now you can see that value for field i is changed only in cloned object not in the original object.

That's all for this topic Object cloning in Java. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Serialization in Java
  2. serialVersionUID and versioning in Java Serialization
  3. Marker interface in Java

You may also like -

>>>Go to Java advance topics page


Saturday, 22 April 2017

Serialization Proxy Pattern in Java

When you serialize an object in Java it is converted to byte stream and object is reconstituted using that byte stream during the process of deserialization.

Sometimes this extraneous behavior of creating object using the byte stream is not what you want and you still want constructor (or any other method if required) to be called when your object is created during the process of deserialization.

Serialization proxy pattern

Serialization proxy pattern is a way to design your class where proxy pattern defines its serialization mechanism.

Before going into any more details about serialization proxy pattern let’s know about two methods.

  • writeReplace()
  • readResolve()

writeReplace() method

Serializable classes that use an alternative object (proxy object) when writing an object to the stream should implement writeReplace() method with the exact signature:

ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException;

This writeReplace() method is invoked by serialization if the method exists and this method is defined within the original class whose object is serialized. Thus, the method can have private, protected and package-private access modifier.

readResolve() method

Classes that need to provide a replacement object when the serialized object is read from the stream should implement readResolve() method with the exact signature.

 ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;

This readResolve() method follows the same invocation rules and accessibility rules as writeReplace.

How Serialization Proxy pattern works

Rather than serializing the original class you provide functionality using the writeReplace() method to serialize the proxy class instead. Here note that writeReplace() method is implemented in the original class.

At the time of deserialization proxy object is deserialized and then the readResolve() method is called. That’s where you will have to provide the functionality to create the original class object regular way. Here note that readResolve() method is implemented in the proxy class.

Proxy class

Generally serialization proxy pattern is implemented by creating a proxy class as a nested static class with in the original class. Since it needs access to the fields of the outer class so that it is better to create proxy class as a nested class.

Example code

Time is right to see an example of the serialization proxy pattern. Here we have a Person class which has a constructor with args. When a Person class object is created it is initialized using this constructor and that’s what you want to do when you deseliarize a serialized Person class object.

For doing that you will use Serialization proxy pattern and create a proxy class (called PersonProxy here) as a nested static class. You will also implement writeReplace() and readResolve() methods.

Person class

import java.io.Serializable;

public class Person implements Serializable{
 
 /**
  * 
  */
 private static final long serialVersionUID = 9140203997753929147L;
 private String name;
 private int id;
 private int age;
 
 // Constructor
 Person(String name, int id, int age){
   System.out.println("In Constructor with args");
   this.name = name;
   this.id = id;
   this.age = age; 
 }
 // no-arg Constructor
 Person(){
   System.out.println("no-arg constructor");
 }
 
 public String getName() {
  return name;
 }
  
 
 public int getAge() {
  return age;
 }
 public int getId() {
  return id;
 }
 /**
  * writeReplace method for the proxy pattern
  * @return
  */
 private Object writeReplace() {
  System.out.println("In writeReplace() method");
  return new PersonProxy(this);
 }
 // Nested static class - Proxy
 private static class PersonProxy implements Serializable {
  /**
   * 
   */
  private static final long serialVersionUID = -5965328891170223339L;
  private String name;
  private int id;
  private int age;
  PersonProxy(Person p) {
   this.name = p.name;
   this.id = p.id;
   this.age = p.age;
  }
  // readResolve method for Person.PersonProxy
  private Object readResolve() {
   System.out.println("In readResolve() method");
   return new Person(name, id, age); // Uses public constructor
  } 
 }
}

Util class

A util class with methods to serialize and deserialize.

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class Util {
  /**
   * Method used for serialization
   * @param obj
   * @param fileName
   */
  public static void serialzeObject(Object obj, String fileName){
   try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File(fileName)))){
    oos.writeObject(obj);
    
   } catch (FileNotFoundException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }
  
  /**
   * Method used for deserializing
   * @param fileName
   * @return
   * @throws ClassNotFoundException
   */
  public static Object deSerialzeObject(String fileName) throws ClassNotFoundException{
   Object obj = null;
   try(ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File(fileName)))){
    obj = ois.readObject();
    
   } catch (FileNotFoundException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   return obj;
  }
}

SerializationDemo class

Using this class a Person class object will be serialized and later deserialized.

public class SerializationDemo {

 public static void main(String[] args) {
  // Creating and initializaing a Person object
    Person person = new Person("User1", 1, 22);
    // file name
    final String fileName = "F://person.ser";
    System.out.println("About to serialize ....");
    // serializing
    Util.serialzeObject(person, fileName);
    
    try {
     System.out.println("About to deserialize ....");
     // deserializing
     person = (Person)Util.deSerialzeObject(fileName);
     System.out.println("id " + person.getId() + " Name "+ person.getName() 
       + " Age " + person.getAge());
    } catch (ClassNotFoundException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
 }
}

Output

In Constructor with args
About to serialize ....
In writeReplace() method
About to deserialize ....
In readResolve() method
In Constructor with args
id 1 Name User1 Age 22

Here you can see that writeReplace() method is called when object is serialized. At the time of deserializing the object readResolve() method is called where object is created and initialized using the constructor of the class not just recreated using the byte stream.

Creating instance by getting data from DB

Another example, which you will see in many frameworks too is when you want your instance to be created using a DB call. In that case what you need to serialize is some identifier only and during deserialization using that identifier you will get the data to construct the object from DB.

Example Code

Here you have a Person class with fields as id, name etc. In writeReplace() method where you serialize the proxy you provide the id also.

Person class

public class Person implements Serializable {
     private int id;
 private String name;
 …
 private Object writeReplace() {
  return new PersonProxy(id);
 }
}

Proxy Class

In the readResolve() method of the proxy class you create the Person class instance using the id which you saved earlier.

public class PersonProxy implements Serializable {
 private int id;
 public PersonProxy(int id) {
  this.id = id;
 }
 public Object readResolve() {
  // DB call to get the person record by id
  return PersonDAO.findById(id);
 }
}

That's all for this topic Serialization Proxy pattern in Java. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. serialVersionUID and versioning in Java Serialization
  2. Serialization in Java
  3. Externalizable interface in Java
  4. Transient in Java
  5. Insert\Update using NamedParameterJDBCTemplate in Spring framework
  6. Select query using NamedParameterJDBCTemplate in Spring framework

You may also like -

>>>Go to Java advance topics page

Wednesday, 19 April 2017

serialVersionUID and versioning in Java Serialization

If you ever implemented Serializable interface then you would have seen the warning “The serializable class XXX does not declare a static final serialVersionUID field of type long”. If you did wonder why this warning then this post will help to understand it.

SerialVersionIUID and versioning

A simple explanation for why do we need to declare serialVersionUID is it helps with versioning.

Suppose you have some class which is serialized and it changes before it is deserialized. You will need to consider what happens in that situation? Can you allow the new version of your class to read old data.

To help with these versioning scenarios serialization process provides a simple versioning mechanism using serialVersionUID.

serialVerionUID generation

The stream-unique identifier is a 64-bit hash of the class name, interface class names, methods, and fields. If you are using IDE like eclipse and you have a class that implements Serializable interface then you will get a warning upfront that serialVersionUID is not declared.

Eclipse will also give you options -

  • to add default serialVersionUID
  • OR
  • to add generated serialVersionUID

In case you choose to ignore that warning even then by default serialization mechanism will generate serialVersionUID, both the name of the class and its serialVersionUID are written to the object stream.

During deserialization again serialVersionUID will be generated and compared with the previously written serialVersionUID, if there is a mismatch that means version is changed and InvalidClassException will be thrown.

Example code

Let’s try to clear it with an example. Suppose you have a Person class with few fields and you serialize the Person class. Now you add a new field in Person and try to deserialize it.

Person class

public class Person implements Serializable{
 private String name;
 private int id;
 private int age;
 /*private String city;
 public String getCity() {
  return city;
 }*/
 // Constructor
 Person(String name, int id, int age){
   System.out.println("In Constructor with args");
   this.name = name;
   this.id = id;
   this.age = age; 
 }
 // no-arg Constructor
 Person(){
   System.out.println("no-arg constructor");
 }
 
 public String getName() {
  return name;
 }
  
 
 public int getAge() {
  return age;
 }
 public int getId() {
  return id;
 }
}

So here is a Person class with fields like id, name and age. It implements Serializable interface and choose to ignore the warning to declare serialVersionUID.

Util class

This is a class with static methods to serialize and deserialize.

public class Util {
  /**
   * Method used for serialization
   * @param obj
   * @param fileName
   */
  public static void serialzeObject(Object obj, String fileName){
   try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File(fileName)))){
    oos.writeObject(obj);
    
   } catch (FileNotFoundException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }
  
  /**
   * Method used for deserializing
   * @param fileName
   * @return
   * @throws ClassNotFoundException
   */
  public static Object deSerialzeObject(String fileName) throws ClassNotFoundException{
   Object obj = null;
   try(ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File(fileName)))){
    obj = ois.readObject();
    
   } catch (FileNotFoundException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   return obj;
  }
}

Now I serialize Person class object using the following test class.

public class SerializationDemo {

 public static void main(String[] args) {
  // Creating and initializaing a Person object
    Person person = new Person("User1", 1, 22);
    // file name
    final String fileName = "F://person.ser";
    // serializing
    Util.serialzeObject(person, fileName);
    
    /*try {
     // deserializing
     person = (Person)Util.deSerialzeObject(fileName);
    } catch (ClassNotFoundException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }*/
 }
}

So far so good, Person class object is created and serialized. Now what you do is to add a new field to Person class.

public class Person implements Serializable{
 private String name;
 private int id;
 private int age;
 private String city;
 
 // Constructor
 Person(String name, int id, int age){
   System.out.println("In Constructor with args");
   this.name = name;
   this.id = id;
   this.age = age; 
 }
 // no-arg Constructor
 Person(){
   System.out.println("no-arg constructor");
 }
 
 public String getName() {
  return name;
 }
  
 
 public int getAge() {
  return age;
 }
 public int getId() {
  return id;
 }
 public String getCity() {
  return city;
 }
}

Here you can see a new field city is added to a Person class.

Now if I try to deserialize the byte stream which was already created before the inclusion of this new field in Person class InvalidClassException will be thrown.

public class SerializationDemo {

 public static void main(String[] args) {
  // Creating and initializaing a Person object
    Person person = new Person("User1", 1, 22);
    // file name
    final String fileName = "F://person.ser";
    // serializing
    //Util.serialzeObject(person, fileName);
    
    try {
     // deserializing
     person = (Person)Util.deSerialzeObject(fileName);
    } catch (ClassNotFoundException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
 }
}
java.io.InvalidClassException: org.netjs.prog.Person; local class incompatible: stream classdesc 
serialVersionUID = -4901887311122736183, local class serialVersionUID = -1818819755742473032
 at java.io.ObjectStreamClass.initNonProxy(Unknown Source)
 at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
 at java.io.ObjectInputStream.readClassDesc(Unknown Source)
 at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
 at java.io.ObjectInputStream.readObject0(Unknown Source)
 at java.io.ObjectInputStream.readObject(Unknown Source)
 at org.netjs.prog.Util.deSerialzeObject(Util.java:39)
 at org.netjs.prog.SerializationDemo.main(SerializationDemo.java:15)

Here note that even if you chose to ignore the warning and didn’t declare the serialVersionUID it is still generated. You can see that 2 different serialVersionUIDs are there as the class has changed and that mismatch has caused the exception.

Assigning serialVersionUID

As shown in the above example if you choose to ignore the warning and rely on generation of serialVersionUID by the serialization mechanism itself it will always fail if there is a change in the class.

That’s why you as an implementor of the class should take charge and assign a serialVersionUID yourself (If you are using IDE like Eclipse that can be generated by Eclipse for you or you can use serialver tool which comes with the JDK to generate serialVersionUID).

With you taking charge when you know your class has changed in a way that it is not compatible with the old version anymore you can choose to change the serialVersionUID. In that case during deserialization because of the non-matching serialVersionUID, InvalidClassException will be thrown.

If you choose not to change the serialVersionUID even if your class has changed as you think the change is not significant then deserialization will proceed with out throwing any exception.

Example code

Let’s take the same example as above but this time serialVersionUID is declared.

Person class

public class Person implements Serializable{
 /**
  * 
  */
 private static final long serialVersionUID = -4046333379855427853L;
 private String name;
 private int id;
 private int age;
 /*private String city;
 public String getCity() {
  return city;
 }*/
 // Constructor
 Person(String name, int id, int age){
   System.out.println("In Constructor with args");
   this.name = name;
   this.id = id;
   this.age = age; 
 }
 // no-arg Constructor
 Person(){
   System.out.println("no-arg constructor");
 }
 
 public String getName() {
  return name;
 }
  
 
 public int getAge() {
  return age;
 }
 public int getId() {
  return id;
 }
}

Now the class is serialized.

public class SerializationDemo {

 public static void main(String[] args) {
  // Creating and initializaing a Person object
    Person person = new Person("User1", 1, 22);
    // file name
    final String fileName = "F://person.ser";
    // serializing
    //Util.serialzeObject(person, fileName);
    
    /*try {
     // deserializing
     person = (Person)Util.deSerialzeObject(fileName);
     System.out.println("id " + person.getId() + " Name "+ person.getName() 
       + " Age " + person.getAge() + " City " + person.getCity());
    } catch (ClassNotFoundException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }*/
 }
}

Now a new field city is added in the Person class but the serialVersionUID remains same as before.

public class Person implements Serializable{
 /**
  * 
  */
 private static final long serialVersionUID = -4046333379855427853L;
 private String name;
 private int id;
 private int age;
 private String city;
 public String getCity() {
  return city;
 }
 // Constructor
 Person(String name, int id, int age){
   System.out.println("In Constructor with args");
   this.name = name;
   this.id = id;
   this.age = age; 
 }
 // no-arg Constructor
 Person(){
   System.out.println("no-arg constructor");
 }
 
 public String getName() {
  return name;
 }
  
 
 public int getAge() {
  return age;
 }
 public int getId() {
  return id;
 }
}

Now deserialization will happen though there won’t be any value for the city field.

public class SerializationDemo {

 public static void main(String[] args) {
  // Creating and initializaing a Person object
    Person person = new Person("User1", 1, 22);
    // file name
    final String fileName = "F://person.ser";
    // serializing
    //Util.serialzeObject(person, fileName);
    
    try {
     // deserializing
     person = (Person)Util.deSerialzeObject(fileName);
     System.out.println("id " + person.getId() + " Name "+ person.getName() 
       + " Age " + person.getAge() + " City " + person.getCity());
    } catch (ClassNotFoundException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
 }
}

Output

In Constructor with args
id 1 Name User1 Age 22 City null

For test you can regenerate the serialVersionUID of the Person class after adding city field. In that case deserialization will fail as there will be a mismatch between serialVersionUIDs.

Points to remember

  1. serialVersionUID is used for versioning of the serialized streams. During serialization process serialVersionUID is also stored. During deserialization generated serialVersionUID is matched with the stored one and if there is a mismatch process fails.
  2. serialVersionUID is a 64-bit hash of the class name, interface class names, methods, and fields. If you don’t declare one yourself serialization process will still generate serialVersionUID. In that case it will fail for any change in the class.
  3. If you declare the serialVersionUID that gives you control over the versioning. When you think class has grown in way that is not compatible with the previous versions then you can change the serialVersionUID. If you think change in the class are not significant enough to change the serialVersionUID you may choose to retain the same serialVersionUID. In that case serialization and deserialization will not fail even if your class had changed.
  4. serialVersionUID is declared as a private static final long and it is always better to declare one in order to have control over the versioning of the class.

That's all for this topic serialVersionUID and versioning in Java Serialization. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Serialization in Java
  2. Transient in Java
  3. Externalizable interface in Java
  4. Serialization Proxy Pattern in Java
  5. Marker interface in Java

You may also like -

>>>Go to Java advance topics page

Monday, 17 April 2017

Externalizable interface in Java

Though serialization in Java provides a pretty good default implementation for serializing and deserializing an object. All you need to do is to implement Serializable interface and the whole process is automatic for you.

But, what if you want to control the process of serialization, you have some fields in your object which hold confidential information and you don’t want to serialize those fields or a sub-object with in your object graph doesn’t need to be serialized. That’s when you can use externalizable interface.

Externalizable interface in Java

Externalizable interface extends the Serializable interface (which is a marker interface) and adds two methods writeExternal() and readExternal().

When you use Externalizable for your serialization, you will implement Externalizable interface and implement writeExternal() and readExternal() methods. These two methods will be called while serializing and deserializing respectively.

General form of writeExternal() and readExternal()

  • readExternal(ObjectInput in) - The object implements the readExternal method to restore its contents by calling the methods of DataInput for primitive types and readObject for objects, strings and arrays.
  • writeExternal(ObjectOutput out) - The object implements the writeExternal method to save its contents by calling the methods of DataOutput for its primitive values or calling the writeObject method of ObjectOutput for objects, strings, and arrays.

Refer Serialization in Java to see another way, using readObject and writeObject to control the process of serialization.

Serialization process when Externalizable interface is used

Each object to be stored is tested for the Externalizable interface. If the object supports Externalizable, the writeExternal method is called. If the object does not support Externalizable and does implement Serializable, the object is saved using ObjectOutputStream.

When an Externalizable object is reconstructed, an instance is created using the public no-arg constructor, then the readExternal method called. Serializable objects are restored by reading them from an ObjectInputStream.

Example code

Let’s see an example where we have a class called User in which pwd field is there that you don’t want to convert into bytes. Though that can also be done by marking it as transient but here let us see how Externalizable can be used to control the serialization.

User class

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;

public class User implements Externalizable {
 private String userName;
 private int id;
 private String pwd;
 
 // no-arg constructor **Required**
 public User(){
  System.out.println("In no-arg constructor");
 }
 
 public User(String userName, int id, String pwd){
  System.out.println("In constructor with args");
  this.userName = userName;
  this.id = id;
  this.pwd = pwd;
 }
 
 public String getUserName() {
  return userName;
 }

 public int getId() {
  return id;
 }

 public String getPwd() {
  return pwd;
 }

 @Override
 public void writeExternal(ObjectOutput out) throws IOException {
  System.out.println("In writeExternal method");
  out.writeObject(userName);
  out.writeInt(id);
 }

 @Override
 public void readExternal(ObjectInput in) throws IOException,
   ClassNotFoundException {
  System.out.println("In readExternal method");
  userName = (String)in.readObject();
  id = in.readInt();
 
 }
}

ExternalizableDemo class

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class ExternalizableDemo {

 public static void main(String[] args) {
  User user = new User("TestUser", 1, "pwd");
  try {
   ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("test.ser"));
   oos.writeObject(user);
   oos.close();
   
   ObjectInputStream ois = new ObjectInputStream(new FileInputStream("test.ser"));

   user = (User)ois.readObject();
   ois.close();
   System.out.println("UserName " + user.getUserName() + " id " 
      + user.getId() + " pwd " + user.getPwd());
   
  } catch (IOException | ClassNotFoundException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 }
}

Output

In constructor with args
In writeExternal method
In no-arg constructor
In readExternal method
UserName TestUser id 1 pwd null

Here you can see that writeExternal() and readExternal() methods are called for serializing and deserializing the object. Now it is upto you to provide implementation for serialization in writeExternal() method where pwd field is excluded.

Points to note here are -

  1. A default no-arg constructor has to be there while using externalizable as object is created using no-arg constructor while deserializing and then the object is initialized using the logic in readExternal() method. Note that it is different from default serialization where object is reconstituted using the byte stream and constructor is not called.
  2. Order that is used in writeExternal() method for writing the fields should be maintained in readExternal() method.

Externalizable with inheritance

One scenario where Externalizable can be used quite effectively is in a parent-child relationship where parent class doesn’t implement the serializable interface but you want the fields that are there in the parent class to be serialized too.

In this case if you create an object of the child class and serialize it using default serialization. Then deserializing it won’t give you any value for the fields which child class object gets by virtue of extending parent class.

Let’s say we have a classA which is the super class and classB which extends classA.

ClassA

public class ClassA {
  private int deptId;
  private String deptName;
  public int getDeptId() {
   return deptId;
  }
  public void setDeptId(int deptId) {
   this.deptId = deptId;
  }
  public String getDeptName() {
   return deptName;
  }
  public void setDeptName(String deptName) {
   this.deptName = deptName;
  }
}

ClassB

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;

public class ClassB extends ClassA implements Externalizable{
 private String empId;
 private String empName;
 public String getEmpId() {
   return empId;
 }
 public void setEmpId(String empId) {
   this.empId = empId;
 }
 public String getEmpName() {
   return empName;
 }
 public void setEmpName(String empName) {
   this.empName = empName;
 }
 @Override
 public void writeExternal(ObjectOutput out) throws IOException {
  System.out.println("In writeExternal method");
  //Writing parent class ClassA fields
  out.writeInt(getDeptId());
  out.writeObject(getDeptName());
  // Writing child class fields
  out.writeObject(getEmpId());
  out.writeObject(getEmpName());
  
 }

 @Override
 public void readExternal(ObjectInput in) throws IOException,
   ClassNotFoundException {
  System.out.println("In readExternal method");
  // Setting parent class fields
  setDeptId(in.readInt());
  setDeptName((String)in.readObject());
  // Setting child class fields
  setEmpId((String)in.readObject());
  setEmpName((String)in.readObject());
 }

}

Test class

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class ExternalizableDemo {

 public static void main(String[] args) {
    final String fileName = "D://test.ser";
    ClassB objb = new ClassB();
    objb.setDeptId(1);
    objb.setDeptName("Finance");
    objb.setEmpId("E001");
    objb.setEmpName("Ram");
  try {
   ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(fileName));
   oos.writeObject(objb);
   oos.close();
   
   ObjectInputStream ois = new ObjectInputStream(new FileInputStream(fileName));

   objb = (ClassB)ois.readObject();
   ois.close();
   System.out.println("DeptId " + objb.getDeptId() + " DeptName " + objb.getDeptName() 
     + " EmpId " + objb.getEmpId() + " EmpName "+ objb.getEmpName());
   
  } catch (IOException | ClassNotFoundException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 }
}

Output

In writeExternal method
In readExternal method
DeptId 1 DeptName Finance EmpId E001 EmpName Ram

Since you can control what is serialized and how, you can make sure that all the fields of super class ClassA are also serialized and deserialized in the writeExternal() and readExternal() methods.

That's all for this topic Externalizable interface in Java. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Serialization in Java
  2. Transient in Java
  3. serialVersionUID and versioning in Java Serialization
  4. Serialization Proxy Pattern in Java
  5. Marker interface in Java

You may also like -

>>>Go to Java advance topics page

Friday, 14 April 2017

Transient in Java

In the post Serialization in Java it has already been discussed that serialization is the mechanism by which any object can be converted to byte stream. By default all of the object variables are converted to bytes and persisted/send across network.

There may be a scenario where you don’t want any of the variable to be part of serialization because that variable may have some sensitive information which you don’t want to persist or send across the network. That variable can be marked as transient.

Transient keyword in Java

If you want to exclude any object field from getting serialized you can use transient keyword along with that field. Note that you cannot use transient keyword with methods or local variables it can only be used with member variables.

Example code

Let’s see an example using transient keyword. Here we have a class called User which has a field pwd which you don’t want to get serialized.

There is a also a class Util that has static methods for serializing and deserializing an object.

User class

import java.io.Serializable;
import java.util.Date;
public class User implements Serializable{
 /**
  * 
  */
 private static final long serialVersionUID = 1L;
 private String userName;
 private Date loginDate;
 // Transient field
 private transient String pwd;
 public String getUserName() {
  return userName;
 }
 public void setUserName(String userName) {
  this.userName = userName;
 }
 public Date getLoginDate() {
  return loginDate;
 }
 public void setLoginDate(Date loginDate) {
  this.loginDate = loginDate;
 }
 public String getPwd() {
  return pwd;
 }
 public void setPwd(String pwd) {
  this.pwd = pwd;
 }

}

Util class

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class Util {
 
 /**
  * Method used for serialization
  * @param obj
  * @param fileName
  */
 public static void serialzeObject(Object obj, String fileName){
  try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File(fileName)))){
   oos.writeObject(obj);
   
  } catch (FileNotFoundException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 }
 
 /**
  * Method used for deserializing
  * @param fileName
  * @return
  * @throws ClassNotFoundException
  */
 public static Object deSerialzeObject(String fileName) throws ClassNotFoundException{
  Object obj = null;
  try(ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File(fileName)))){
   obj = ois.readObject();
   
  } catch (FileNotFoundException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  return obj;
 }

}

Now let’s create a User object and serialize and deserialize it to see what happens to the pwd field.

import java.util.Date;

public class SerializationDemo {
 public static void main(String[] args) {
  // Creating and initializaing a User object
  User user = getUser();
  // file name
  final String fileName = "D://user.ser";
  // serializing
  Util.serialzeObject(user, fileName);
  
  try {
   // deserializing
   user = (User)Util.deSerialzeObject(fileName);
  } catch (ClassNotFoundException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  
  System.out.println("User name " + user.getUserName());
  System.out.println("Login date " + user.getLoginDate());
  System.out.println("Password " + user.getPwd());
  
 }
 
 private static User getUser(){
  User user = new User();
  user.setUserName("TestUser");
  user.setLoginDate(new Date());
  user.setPwd("pwd@123");
  return user;
 }

}

Output

User name TestUser
Login date Mon Apr 03 18:08:49 IST 2017
Password null

If you open the created file “user.ser” you won’t find any trace of pwd variable there.

When to use transient

  1. As mentioned above you can use transient keyword with the variable that holds some confidential value which you don’t want to get persisted in a file or sent across the network.
  2. Any variable that is calculated using other variables. After deserialization you can get the other variables and recalculate the value. One of the example of this can be found in Java Collection framework itself. In code of HashMap class you can see that hash code is calculated again after deserializing the HashMap key and values. Hashcode is not serialized but recalculated in that case.

    Example code

    Let’s say you have a Person bean where you have both Date Of Birth and age fields. In that case age can be calculated again using the DOB and current date rather than serializing the age. If you are serializing the Person object for long age may be wrong if taken from the deserialized object.

    Person class

    import java.io.Serializable;
    import java.util.Date;
    
    public class Person  implements Serializable{
    
     /**
      * 
      */
     private static final long serialVersionUID = 1L;
     private String name;
     private Date dob;
     // transient
     private transient int age;
     public String getName() {
      return name;
     }
     public void setName(String name) {
      this.name = name;
     }
     public Date getDob() {
      return dob;
     }
     public void setDob(Date dob) {
      this.dob = dob;
     }
     public int getAge() {
      return age;
     }
     public void setAge(int age) {
      this.age = age;
     }
     
    }
    

    SerializationDemo class

    import java.text.DateFormat;
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.time.LocalDate;
    import java.time.temporal.ChronoUnit;
    import java.util.Calendar;
    import java.util.GregorianCalendar;
    
    public class SerializationDemo {
     public static void main(String[] args) {
      // Creating and initializaing a Person object
      Person person = getPerson();
      // file name
      final String fileName = "D://person.ser";
      // serializing
      Util.serialzeObject(person, fileName);
      
      try {
       // deserializing
       person = (Person)Util.deSerialzeObject(fileName);
      } catch (ClassNotFoundException e) {
       // TODO Auto-generated catch block
       e.printStackTrace();
      }
      
      System.out.println("Name " + person.getName());
      System.out.println("DOB " + person.getDob());
      System.out.println("Age " + person.getAge());
      
      int age = (int)calculateAge(person);
      System.out.println("age " +age);
      
      
     }
     
     /**
      * Method for getting person record
      * @return
      */
     private static Person getPerson(){
      Person person = new Person();
      DateFormat df = new SimpleDateFormat("dd/MM/yyyy");
      try {
       person.setDob(df.parse("04/04/2015"));
      } catch (ParseException e) {
       // TODO Auto-generated catch block
       e.printStackTrace();
      }
      person.setName("TestUser");
      return person;
     }
     
     /**
      * Method for calculating age
      * @param person
      * @return
      */
     private static long calculateAge(Person person){
      // creating a calendar instance with DOB
      Calendar firstCal = GregorianCalendar.getInstance();
      firstCal.setTime(person.getDob());
      // Calculating difference in years
      long num = ChronoUnit.YEARS.between( LocalDate.of(firstCal.get(Calendar.YEAR), firstCal.get(Calendar.MONTH), 
         firstCal.get(Calendar.DAY_OF_MONTH)) , LocalDate.now()) ;
      
      return num;
     }
    
    }
    

    Util class is already given above with the serialize() and deserialize() methods.

    Output

    Name TestUser
    DOB Sat Apr 04 00:00:00 IST 2015
    Age 0
    age 2
    
    You can see in the output initially age is 0 after deserialization as age was marked as transient. It’s later calculated using the DOB and current date.
  3. You may have instances that have no meaning if serialized. Like a logger instance, a resource bundle, a properties instance with property values.

That's all for this topic Transient in Java. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Serialization in Java
  2. Externalizable interface in Java
  3. serialVersionUID and versioning in Java Serialization
  4. Serialization Proxy Pattern in Java

You may also like -

>>>Go to Java advance topics page

Wednesday, 12 April 2017

Serialization in Java

Object serialization is the mechanism of converting object into byte stream. Where as the reverse process of constituting the object from those bytes is known as deserialization.

Use of serialization

Once an object is converted to a byte stream those bytes can be -

  1. Transmitted from one JVM to another where the object can be reconstituted using those bytes and used in further processing.
  2. Stored on a disk/DB for further use.
Serialization in Java
Serialization in Java

Portability

One important feature of serialization is the portability it offers. When a serialized object is transmitted across the network the serialization mechanism will take into account the differences in operating systems. Thus an object converted into byte streams in Windows OS can be transmitted across the network and deserialized into an object in the Unix operating system.

Serializable interface

A mandatory requirement for a class object to be able to be serialized is that the class should implement Serializable interface which is part of java.io package.

Here note that Serializable is a marker interface and does not have any field or method.

Steps involved in Serialization of an object

In order to serialize an object you need an object of ObjectOutputStream and an object of OutputStream to be wrapped inside ObjectOutputStream object. Then you need to call writeObject() method which will serialize your object and send it to OutputStream.

Steps involved in Deserialization of an object

In order to deserialize an object you need an object of ObjectInputStream and an object of InputStream to be wrapped inside ObjectInputStream object. Then you need to call readObject() method which will reconstitute your object from the byte stream.

Example code

Let’s see an example of serialization, here we have an Address bean with fields like addressline1, city etc. and a Person bean that along with other fields also has an instance of address class. That way you can see that the whole object graph is serialized.

Then we have Util class with the methods to serialize and deserialize an object. Also the test class SerializationDemo to execute the code.

Address class

public class Address implements Serializable{
 private String addressLine1;
 private String addressLine2;
 private String city;
 private String state;
 private String country;
 
 Address(String addressLine1, String addressLine2, String city, String state, String country){
  this.addressLine1 = addressLine1;
  this.addressLine2 = addressLine2;
  this.city = city;
  this.state = state;
  this.country = country;
 }
 public String getAddressLine1() {
  return addressLine1;
 }

 public String getAddressLine2() {
  return addressLine2;
 }
 
 public String getCity() {
  return city;
 }
 
 public String getState() {
  return state;
 }
 
 public String getCountry() {
  return country;
 }

}

Person class

public class Person implements Serializable{

 /**
  * 
  */
 private static final long serialVersionUID = 1L;
 private String name;
 private Date dob;
 // transient
 private transient int age;
 private Address address;
 // Constructor
 Person(String name, Date dob, int age, Address address){
  System.out.println("In Constructor with args");
  this.name = name;
  this.dob = dob;
  this.age = age;
  this.address = address;
    
 }
 // no-arg Constructor
 Person(){
  System.out.println("no-arg constructor");
 }
 
 public Address getAddress() {
  return address;
 }

 public String getName() {
  return name;
 }
 
 public Date getDob() {
  return dob;
 }
 
 public int getAge() {
  return age;
 }
}

Util class

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class Util {
 
 /**
  * Method used for serialization
  * @param obj
  * @param fileName
  */
 public static void serialzeObject(Object obj, String fileName){
  try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File(fileName)))){
   oos.writeObject(obj);
   
  } catch (FileNotFoundException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 }
 
 /**
  * Method used for deserializing
  * @param fileName
  * @return
  * @throws ClassNotFoundException
  */
 public static Object deSerialzeObject(String fileName) throws ClassNotFoundException{
  Object obj = null;
  try(ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File(fileName)))){
   obj = ois.readObject();
   
  } catch (FileNotFoundException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  return obj;
 }

}

SerializationDemo class

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;


public class SerializationDemo {
 public static void main(String[] args) {
  DateFormat df = new SimpleDateFormat("dd/MM/yyyy");
  Date dob = null;
  try {
   dob = df.parse("04/04/2015");
  } catch (ParseException e1) {
   // TODO Auto-generated catch block
   e1.printStackTrace();
  }
  // Creating and initializaing a Address object
  Address address = new Address("#34", "ABC Street", "New Delhi", "Delhi", "India");
  // Creating and initializaing a Person object
  Person person = new Person("User1", dob, 2, address);
  // file name
  final String fileName = "D://person.ser";
  // serializing
  Util.serialzeObject(person, fileName);
  
  try {
   // deserializing
   person = (Person)Util.deSerialzeObject(fileName);
  } catch (ClassNotFoundException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  System.out.println("deserialized object ---- ");
  System.out.println("Name " + person.getName());
  System.out.println("DOB " + person.getDob());
  System.out.println("Age " + person.getAge());
  System.out.println("Address Line1 " + person.getAddress().getAddressLine1());
  System.out.println("Address Line2 " + person.getAddress().getAddressLine2());
  System.out.println("City " + person.getAddress().getCity());
  System.out.println("State " + person.getAddress().getState());
  System.out.println("Country " + person.getAddress().getCountry());
  
  
 }

}

Output

In Constructor with args
deserialized object ---- 
Name User1
DOB Sat Apr 04 00:00:00 IST 2015
Age 0
Age #34
Age ABC Street
Age New Delhi
Age Delhi
Age India

Here you specify the file name and then pass the person object and the file name to the serializeObject method of the Util class which will do the process of serialization. Again you pass the filename which already has the stored bytes for the person object to the deSerializeObject method of the Util class which will deserialize the serialized person object.

Points to note here

  • Here you can see in person object there is a reference to address object and both are serialized which shows the whole object graph gets serialized even if there is a very complex hierarchy.
  • All the classes which are to be serialized should be implementing Serializable interface. In this example suppose Address class doesn’t implement Serializable interface and there is a reference of it in Person class then you will get exception when you try to serialize the person object.
    java.io.NotSerializableException: org.test.Address
  • If you have noticed in Person class there is a system.println in both with args and no-arg constructors. When the object is deserialized you can see even default no-arg constructor is not called. Though reiterated several times I’ll repeat it again that object is reconstituted from the serialized bytes while deserializing and no constructor is called during the process of deserialization.
  • In Person class age field is marked as transient which stops this field from getting serialized. That’s why you can see age is printed as 0.

    Refer Transient in Java to know more about transient keyword.

writeObject( ) and readObject( ) methods

If you want to have some control over the process of serialization and deserialization rather than using the default serialization mechanism which for us, as end user, is automatic then you can add writeObject() and readObject() methods.

If you add methods writeObject() and readObject(), these methods will be called automatically when the object is serialized and deserialized respectively and provide the serialization mechanism rather than using the default mechanism.

General form

private void writeObject(ObjectOutputStream oos) throws IOException

private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException

Example code

One scenario where these methods can be used quite effectively is in a parent-child relationship where parent class doesn’t implement the serializable interface but you want the fields that are there in the parent class to be serialized too.

Let’s say we have a classA which is the super class and classB which extends classA.

ClassA

public class ClassA {
 private int deptId;
 private String deptName;
 public int getDeptId() {
  return deptId;
 }
 public void setDeptId(int deptId) {
  this.deptId = deptId;
 }
 public String getDeptName() {
  return deptName;
 }
 public void setDeptName(String deptName) {
  this.deptName = deptName;
 }
 
}

ClassB

import java.io.Serializable;

public class ClassB extends ClassA implements Serializable{
 /**
  * 
  */
 private static final long serialVersionUID = 7280011452607087533L;
 private String empId;
 private String empName;
 public String getEmpId() {
  return empId;
 }
 public void setEmpId(String empId) {
  this.empId = empId;
 }
 public String getEmpName() {
  return empName;
 }
 public void setEmpName(String empName) {
  this.empName = empName;
 }
 
}

In this case if you create a ClassB object and serialize it. Then deserializing it won’t give you any value for the fields which ClassB object gets by virtue of extending ClassA.

public class TestSerialize{
 
 public static void main(String[] args) {
  final String fileName = "D://test.ser";
  ClassB objb = new ClassB();
  objb.setDeptId(1);
  objb.setDeptName("Finance");
  objb.setEmpId("E001");
  objb.setEmpName("Ram");
  Util.serialzeObject(objb, fileName);
  try {
   objb = (ClassB)Util.deSerialzeObject(fileName);
  } catch (ClassNotFoundException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  System.out.println("DeptId " + objb.getDeptId() + " DeptName " + objb.getDeptName());
  System.out.println("EmpId " + objb.getEmpId() + " EmpName " + objb.getEmpName());
 }

}

Output

DeptId 0 DeptName null
EmpId E001 EmpName Ram

You can see that the deptId and deptName fields which are in ClassA are not serialized as ClassA doesn’t implement Serializable interface.

In this case you will have to add writeObject and readObject methods and provide functionality so that the fields of ClassA are also serialized. So, your updated ClassB with writeObject() and readObject() methods added will look like –

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class ClassB extends ClassA implements Serializable{
 /**
  * 
  */
 private static final long serialVersionUID = 7280011452607087533L;
 private String empId;
 private String empName;
 public String getEmpId() {
  return empId;
 }
 public void setEmpId(String empId) {
  this.empId = empId;
 }
 public String getEmpName() {
  return empName;
 }
 public void setEmpName(String empName) {
  this.empName = empName;
 }
 
 // adding writeObject method
 private void writeObject(ObjectOutputStream oos) throws IOException{
  // calling default functionality for classB fields
  oos.defaultWriteObject();
  // Explicitly writing ClassA fields
  oos.writeInt(getDeptId());
  oos.writeObject(getDeptName());
 }
 
 // adding readObject method
 private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException{
  // calling default functionality for classB fields
  ois.defaultReadObject();
  // Explicitly reading ClassA fields and setting them
  setDeptId(ois.readInt());
  setDeptName((String)ois.readObject());
 }
}

Output

DeptId 1 DeptName Finance
EmpId E001 EmpName Ram

Running it using the TestSerialize class will now give you proper output.

Points to note here

  1. One thing to be careful about here is that the order of reading the fields should be same as the order they were written.
  2. You can use defaultWriteObject() and defaultReadObject() as the first statement in writeObject() and readObject() methods respectively for using the default serialization mechanism.

That's all for this topic Serialization in Java. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Externalizable interface in Java
  2. Transient in Java
  3. serialVersionUID and versioning in Java Serialization
  4. Serialization Proxy Pattern in Java
  5. Marker interface in Java

You may also like -

>>>Go to Java advance topics page