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

No comments:

Post a Comment