Object Persistence in Java

Introduction

At the time of development, sometimes it is necessary to store the state of the object in the file system. Some objects may or may not be stored in the file system depending upon the structural intensity of the object graph. In this article, I will focus on two major aspects of the object persistence. Before going to this subject, I would like to tell you about the significance of the object persistence. Object persistence presupposes the state of the object in the file system. In this matter you can make argument regarding object persistence in the database, which hibernate does. But so far this article is concerned I will give glimpse on persistence in the file system for all convenience. The state of object signifies the attributes or properties of the object in the broader sense. The object graph represents the internal morphological structure of the object. So persisting object means, you are going to store all the internal changed structure of the object.

Technicalities
There are several ways you can persist the state of the object. You can take help from Java IO system to store the object in the file system. However there are convenient approaches you can meet your expectations in this regard. One way is the textual representation of the object graph in the file system and another way is the binary representation of the object graph. These ways are very much convenient and easy from the view point of development. You can achieve the textual representation of the object graph using XMLEncoder and you can achieve the binary representation of the object graph using java object serialization process. Let me explain the two approaches below.

Persistence using XMLEncoder

XMLEncoder class is an approach to persist the object graph in an XML document or simply in an XML file. It provides the flexibility of storing the object as a textual approach. In this approach you can see the XML file and you can easily understand the attributes of the object. Similarly to obtain the object graph from the XML file, you can use XMLDecoder. All these classes have been defined in the java.beans package. Let me clarify all the aspects by citing the complete example.

Create a normal java bean or class having the following structure.

Let us see the class called Emp.java which is a normal java bean.

There is another test harness class called TestPersistence.java which exposes the use of XMLEncoder and XMLDecoder.

The following is the Emp.java.

package com.core.persist;

/**

* This is a simple java bean.

* @author Debadatta Mishra(PIKU)

*

*/

public class Emp

{

private String name = null;

private int age = 0;

private String empId = null;

public Emp()

{

super();

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

public String getEmpId() {

return empId;

}

public void setEmpId(String empId) {

this.empId = empId;

}

}

The following is the TestPersistence.java

package com.core.persist;

import java.beans.XMLDecoder;

import java.beans.XMLEncoder;

import java.io.BufferedInputStream;

import java.io.BufferedOutputStream;

import java.io.FileInputStream;

import java.io.FileOutputStream;

/**

* This is a test harness class to display the

* use of XMLEncoder and XMLDecoder.

* @author Debadatta Mishra(PIKU)

*

*/

public class TestPersistence

{

public static void main(String[] args)

{

Emp emp = new Emp();

emp.setName(“John”);

emp.setAge(23);

emp.setEmpId(“A123”);

try

{

/*

* The following codes are used to persist the Emp object graph

*/

XMLEncoder encoder = new XMLEncoder(new BufferedOutputStream(

new FileOutputStream(“C:/emp.xml”)));

encoder.writeObject(emp);

encoder.flush();

encoder.close();

/*

* The following codes are used to obtain the Emp object graph

* from the XML document

*/

XMLDecoder decoder = new XMLDecoder(new BufferedInputStream(

new FileInputStream(“C:/emp.xml”)));

Emp emp1 = ( Emp )decoder.readObject();

decoder.close();

System.out.println(“Emp Name=>”+emp1.getName());

System.out.println(“Emp Age=>”+emp1.getAge());

System.out.println(“Emp Id=>”+emp1.getEmpId());

}

catch( Exception e )

{

e.printStackTrace();

}

}

}

The following is the output of the above example.

If you run the above classes, an XML document called emp.xml will be created in the specified location. The xml document will look like the following.

23

A123

John

So you have stored the state of the Emp object in the xml document. It is also required to load the Emp object from the xml document. For this purpose you have use XMLDecoder which has been used in the test harness class. If you want to test the above two classes, you can copy the classes and change the package structure and you can run it. In case of loading the object using XMLDecoder, it takes help from java’s reflection system.

Advantages of XMLEncoder and XMLDecoder

• Since it is a textual representation of the object graph, anybody can see the XML file and it helps in the portability to any other system.

• If you want to change the value of a particular property of an object, you can do it directly in the XML document so that while using XMLDecoder, you will get your modified value.

• If the object’s variables are declared transient, still you are able to store the complete object graph along with the transient variable’s value. This case is not possible in case of java object serialization.

• It is also very easy and convenient in case of object inheritance. There is no need to bother about the super class and sub class. Some of the limitations of normal java object serialization can be over come in this approach.

Persistence using Serialization

Serialization is a java’s default mechanism to save the state of the object or simply the object graph in the file system. In this case your object will be persisted in the file system where the file is not human readable. It means that you are going to store the binary representation of the object graph in the file system. This object serialization can be achieved using the writeObject() method of the class ObjectOutputStream. The main thing you have to remember is that the object you are going to persist must implement Serialization interface which is called as marker interface. In next article I will explain you the use and the beauty of the marker interfaces. Similarly deserialization means retrieval of object from the saved state. You can achieve the deserialization using readObject() method of the ObjectInputStream class.

Please refer below the following piece of code to achive serialization.

The following is class called Emp. It implements Serializable interface. There is another class called TestSerialization. This class performs both serilization and deserilization. This is the normal way of serilization concept from java.

package com.core.persist;

import java.io.Serializable;

/**

* This is a simple java bean.

* @author Debadatta Mishra(PIKU)

*

*/

public class Emp implements Serializable

{

private static final long serialVersionUID = -164971138528601769L;

private String name = null;

private int age = 0;

public Emp()

{

super();

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

}

Class TestSerialization.java

package com.core.persist;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.ObjectInputStream;

import java.io.ObjectOutputStream;

public class TestSerialization

{

public static void main(String[] args)

{

Emp emp = new Emp();

emp.setAge(23);

emp.setName(“John”);

try

{

/*

* Code to serialize or persist the object

*/

ObjectOutputStream ous = new ObjectOutputStream( new FileOutputStream(“D:/test.ser”));

ous.writeObject(emp);

ous.close();

/*

* Code to deserialize the object

*/

ObjectInputStream oin = new ObjectInputStream( new FileInputStream(“D:/test.ser”));

Emp emp1 = ( Emp )oin.readObject();

System.out.println(“Emp age—-“+emp1.getAge());

System.out.println(“Emp Name—-“+emp1.getName());

}

catch( Exception e )

{

e.printStackTrace();

}

}

}

You can run the above code in your editor to test the functionalities relating to serialization.

Now I put forward some cases for seriliazation.

Case-1:

If your object does not implement Serializable interface,

In order to serialize an object, it is a must that the class must implement seriliazable interface. This is the required principle of serilization. Oterwise it will throw NotSerializationException.

There is another way, if your class does not implement Serilizable interface, you have to declare the object as transient. So that that object state will not be persisted.

Case-2:

In case of inheritance, your super class does not implement Serializable interface and sub class also does not.

In this case serilization will not happen . If you are interested to store the all the properties of the object you can go for XMLEncoder and XMLDecoder as I have alredy explained you.
Case-3:

In case of inheritance, your class implements Serializable interface and sub class does not.

In this case, you should not worry about it, seriliazation happens.

Case-4:

In case of inheritance, your super class does not implement Serializable interface but your sub class does.

Seriliazation will happen but with a lemon falvour. Here no exception will be thrown but your super class data members or object properties of your super class will be not be persisted. When you deserialize object, you will get the default values of your super class object.

Case-5:

This is the best case. You super class and sub class implement serializable interface.

Everything is fine here, serilization happens.

Case-6:

If your object uses transient modifiers inside the objects,

You have to remember that transient objects or variables will not be persisted in case of serialization.

Case-7:

If your object uses volatile modifiers inside the object,

There is nothing to worry about, serialization will happen normally and data will be persisted.

Case-8:

If your object uses static modifiers inside the object,

You have to remember that,since static is not a part of object, so static variables or static object reference will not be persisted in case of seriaization.

Case-9:

It is a very special case I am going to focus on. You may encounter the following situations at the time of serialization.

• You are not sure whether your super class does implement serializable interface.

• You do not have access to the source code of your super class.

• Your super class may be a final class.

• Your super class may contain noe-serializable object reference.

In this case, if you feel frustration and disappointment, you can go for XMLEncoder and XMLDecoder as I have already explained.

If you want to persist the object using java’s serialization concept and mechanism, you have to do it little bit intelligently and manually.

Please refer to the following piece of code.

The following class name is Emp.java

package com.core.persist;

import java.io.ObjectInputStream;

import java.io.ObjectOutputStream;

import java.io.Serializable;

/**

* This is a simple java bean.

* @author Debadatta Mishra(PIKU)

*

*/

public class Emp implements Serializable

{

private static final long serialVersionUID = -164971138528601769L;

private String name = null;

private int age = 0;

private String empId = null;

private transient Project proj = null;

public Emp()

{

super();

proj = new Project();

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

public String getEmpId() {

return empId;

}

public void setEmpId(String empId) {

this.empId = empId;

}

public Project getProj() {

return proj;

}

public void setProj(Project proj) {

this.proj = proj;

}

/**You are proividing a default callback method

* for manual seriallization process.

* @param os of type {@link ObjectOutputStream}

* @throws Exception of type {@link Exception}

*/

private void writeObject( ObjectOutputStream os ) throws Exception

{

try

{

os.defaultWriteObject();

os.writeInt( proj.getProjectId());

os.writeObject( proj.getPojectName() );

}

catch( Exception e )

{

e.printStackTrace();

}

}

/**You are providing default desrialization with

* some manual twik.

* @param oin of type {@link ObjectInputStream}

* @throws Exception of type {@link Exception}

*/

private void readObject( ObjectInputStream oin ) throws Exception

{

try

{

oin.defaultReadObject();

proj = new Project();

proj.setProjectId(oin.readInt());

proj.setPojectName( (String) oin.readObject() );

}

catch( Exception e )

{

e.printStackTrace();

}

}

}

The following class name is Project.java

package com.core.persist;

/**

* @author Debadatta Mishra(PIKU)

*

*/

public class Project

{

private int projectId = 0;

private String pojectName = null;

public Project()

{

super();

}

public String getPojectName() {

return pojectName;

}

public void setPojectName(String pojectName) {

this.pojectName = pojectName;

}

public int getProjectId() {

return projectId;

}

public void setProjectId(int projectId) {

this.projectId = projectId;

}

}

The following class name is TestSerialization.java which is test harness class.

package com.core.persist;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.ObjectInputStream;

import java.io.ObjectOutputStream;

/**

* @author Debadatta Mishra(PIKU)

*

*/

public class TestSerialization

{

public static void main(String[] args)

{

Emp emp = new Emp();

emp.setAge(23);

emp.setEmpId(“A1”);

emp.setName(“John”);

Project proj = new Project();

proj.setProjectId(5555);

proj.setPojectName(“XYZ”);

emp.setProj(proj);

try

{

ObjectOutputStream ous = new ObjectOutputStream(

new FileOutputStream(“D:/test.ser”));

ous.writeObject(emp);

ous.close();

ObjectInputStream oin = new ObjectInputStream(new FileInputStream(

“D:/test.ser”));

Emp emp1 = ( Emp )oin.readObject();

System.out.println(“Emp age—-“+emp1.getAge());

Project proj1 = emp1.getProj();

System.out.println(“Proj Id—–“+proj1.getProjectId());

System.out.println(“Proj Name—-“+proj1.getPojectName());

}

catch( Exception e )

{

e.printStackTrace();

}

}

}

Please see the two methods writeObject() and readObject() inside the class Emp. These two methods are significant in the sense that you are going to achieve serialization with your default object as well as manual serialization with the non serializable object with some data. When you call the methods writeObject() and readObject() for a particular object these methods will be invoked automatically and will persist some default data. In these particular methods you are persisting data manually and thereby making the whole object serializable.

Conclusion

I hope that you will enjoy my article. If you find any problems or errors, please feel free to send me a mail in the address debadattamishra@aol.com . This article is only meant for those who are new to java development. This article does not bear any commercial significance. Please provide me the feedback about this article.

Debadatta Mishra
An aggressive java developer with a difference

Leave a Reply

Your email address will not be published. Required fields are marked *