Welcome!

Related Topics: Java IoT

Java IoT: Article

Java Serialization

Lesson 7, Java Basics

In lessons 5 and 6 of this series, you've learned how to use some of the Java streams to read or write bytes, characters or numeric data. This lesson is about reading or writing entire Java objects into streams.

Let's say your application uses a class that looks like this:

class Employee {
 String lName;
 String fName;
 double salary;
 java.util.Date hireDate;
 String address;
}

Now consider the following scenario: a program HeadQuarterEmpProcessor creates an instance of the object Employee. The values of its attributes (object's state) have to be saved in a file or some other stream. Later on, another program called BranchEmpProcessor needs to recreate the instance of this object Employee in memory.

We could have done it by using one of the streams like DataOutputStream, FileWriter or others. In this case both programs would need to know a format of the saved file (data types, order of the attributes and delimiters). Luckily, Java offers a more elegant way called object serialization, which greatly simplifies the process of objects exchange.

To send the entire object to a stream a program can use the class java.io.ObjectOutputStream, while the class java.io.ObjectInputStream knows how to get an object from a stream. To serialize an object means to convert it into a set of bytes and send it to a stream. To deserialize and object means to read these bytes from a stream and recreate the instance of the received object.

How to Make a Class Serializable

To make a class serializable, just declare that this class implements the interface Serializable:

class Employee implements java.io.Serializable {
 String lName;
 String fName;
 double salary;
 java.util.Date hireDate;
 String address;
}

The good news is that Serializable interface does not force you to implement any methods, that's why modification of the class Employee was minimal.

All attributes of the class Employee must have either primitive data types, or represent objects that are also serializable.

How to Serialize an Object

To serialize an object into a stream perform the following actions:

  • Open one of the output streams, for example FileOutputStream
  • Chain it with the ObjectOutputStream
  • Call the method writeObject() providing the instance of a Serializable object as an argument.
  • Close the streams

    The following example performs all these steps and creates a snapshot of the object Employee in the file called NewEmployee.ser

    import java.io.*;
    import java.util.Date;
    
    public class HeadQuarterEmpProcessor {
    
     public static void main(String[] args) {
    	Employee emp = new Employee();
    	emp.lName = "John";
    	emp.fName = "Smith"; 
    	emp.salary = 50000;
          emp.address = "12 main street";
          emp.hireDate = new Date(); 
        
          FileOutputStream fOut=null;
          ObjectOutputStream oOut=null;
    	   
          try{
           fOut= new FileOutputStream("c:\\NewEmployee.ser");
    	 oOut = new ObjectOutputStream(fOut);
    	 oOut.writeObject(emp);  //serializing employee
    	 System.out.println(
            "An employee is serialized into c:\\NewEmployee.ser");
          }catch(IOException e){
    	  e.printStackTrace(); 
          }finally{
      	  try {
    	    oOut.flush();
    	    oOut.close();
    	    fOut.close();
    	  } catch (IOException e1) {
    	   e1.printStackTrace();
    	  }
    	}
        }
    }
    

    If you do not want to serialize sensitive information such as salary, declare this variable using the keyword transient:

    transient double salary;

    The values of static and transient member variables are not serialized.

    How to Deserialize an Object

    To deserialize an object, perform the following steps:

  • Open an input stream
  • Chain it with the ObjectInputStream
  • Call the method readObject() and cast the returned object to the class that is being deserialized.
  • Close the streams

    The next example reads our file NewEmployee.ser and recreates the instance of the object Employee:

    import java.io.*;
    
    public class BranchEmpProcessor {
    
      public static void main(String[] args) {
       FileInputStream fIn=null;
       ObjectInputStream oIn=null;
    	   
       try{
        fIn= new FileInputStream("c:\\NewEmployee.ser");
        oIn = new ObjectInputStream(fIn);
       
        //de-serializing employee
        Employee emp = (Employee) oIn.readObject();
    				 
        System.out.println("Deserialized " + emp.fName + " " 
                     + emp.lName + " from NewEmployee.ser ");
       }catch(IOException e){
    	  e.printStackTrace(); 
       }catch(ClassNotFoundException e){
            e.printStackTrace(); 
       }finally{
    	try {
            oIn.close();
    	  fIn.close();
    	} catch (IOException e1) {
    	  e1.printStackTrace();
    	}
       }
     }
    }
    

    The class BranchEmpProcessor will produce the following output:

    Deserialized Smith John from NewEmployee.ser

    Please note that we did not explicitly created an instance of the object Employee - JVM did it for us. Make sure that definition of the class Employee is available to JVM that reads the stream. In distributed applications it usually runs on a remote machine.

    During the process of deserialization all transient variables will be initialized with default values according to their type, for example, integer variables will have the value of zero.

    Interface Externalizable

    The method writeObject() sends all attributes of an object into a stream. This could lead to unnecessary large object footprint, especially if you need to serialize the values only of some of the instance variables. Java provides Externalizable interface that gives you more control over what is being serialized and it can produce smaller object footprint.

    Externalizable interface is a subclass of Serializable.

    This interface defines 2 methods: readExternal() and writeExternal() and you have to implement these methods in the class that will be serialized (Employee). In these methods you'll have to write code that reads/writes only the values of the attributes you are interested in. Programs that perform serialization and deserialization have to write and read these attributes in the same sequence.

    The following class Employee2 serializes only the values of the last name and salary.

    import java.io.ObjectOutput;
    import java.io.ObjectInput;
    class Employee2 implements Externalizable {
     String lName;
     String fName;
     double salary; 
     java.util.Date hireDate;
     String address;
     
      public void writeExternal(ObjectOutput stream)
      				 throws java.io.IOException {
      // Serializing only salary and last name  
       stream.writeDouble(salary); 
       stream.writeUTF(lName);  // String encoded in UTF-8 format
      }
    
     public void readExternal(ObjectInput stream)
     				 throws java.io.IOException {
          salary = stream.readDouble();  
    	  lName  = stream.readUTF();
     }
    
    }
    

    The class HeadQuaterEmpProcessor2 shows how to externalize the object Employee2:

    import java.io.*;
    import java.util.Date;
    
    public class HeadQuarterEmpProcessor2 {
    
    	public static void main(String[] args) {
    		Employee2 emp = new Employee2();
    		emp.fName = "John";
    		emp.lName = "Smith"; 
    		emp.salary = 50000;
    	    emp.address = "12 main street";
    	    emp.hireDate = new Date(); 
        
    	   FileOutputStream fOut=null;
    	   ObjectOutputStream oOut=null;
    	   
    	   try{
    	     fOut= new FileOutputStream("c:\\NewEmployee2.ser");
    	     oOut = new ObjectOutputStream(fOut);
    	     emp.writeExternal(oOut);  //serializing employee
    	     System.out.println(
                "An employee is serialized into c:\\NewEmployee2.ser");
    
    	   }catch(IOException e){
    	   	  e.printStackTrace(); 
    	   }finally{
    		try {
    			oOut.flush();
    			oOut.close();
    			fOut.close();
    		} catch (IOException e1) {
    			e1.printStackTrace();
    		}
    	   }
    	}
    }
    

    Unlike with Serializable interface, we had to write a little more code to implement Externalizable interface, but the size of the file NewEmployee2.ser is only 21 bytes, whereas the file NewEmployee.ser has 207 bytes. First of all, we serialized the values of only two attributes, and the other reason is that files created using Externalizable interface contain data only, while files created by default Java serialization contain class metadata that include attribute names.

    The next code snippet shows you how to recreate an externalized object:

    fIn= new FileInputStream("c:\\NewEmployee2.ser");
    oIn = new ObjectInputStream(fIn);
    
    Employee2 emp = new Employee2();
    emp.readExternal(oIn);
    

    Serialization in the Real World

    In some types of applications you have to write the code to serialize objects, but in many cases serialization is performed behind the scenes by various server-side containers. These are some of the typical uses of serialization:

  • To persist data for future use.
  • To send data to a remote computer using such client/server Java technologies as RMI or socket programming.
  • To "flatten" an object into array of bytes in memory.
  • To exchange data between applets and servlets.
  • To store user session in Web applications.
  • To activate/passivate enterprise java beans.
  • To send objects between the servers in a cluster.

    When you use serialization in time-critical applications, for example real-time stock trading systems, the size of the serialized objects should be minimal. Keep in mind that variables with longer names produce larger footprints during serialization, and this may substantially slow down your application. Think of a high volume of trade orders that is being serialized. I remember working on the application where a class TradeOrder had about a hundred member variables. After renaming the variables into meaningless v1, v2, and so on, the size of one TradeOrder instance was reduced by a thousand bytes. And we are talking about serializing of thousands orders over the network!

    If performance is your primary goal, use Externalizable interface instead of Serializable. Yes, you'll have to write code to serialize each attribute, but this may speed up serialization process substantially.

    While applets can connect to a remote computer using socket or RMI programming (these technologies will be explained in the future lessons of this series), HTTP protocol and such Java classes as URL and URLConnection simplify network programming. With an HTTP protocol, applets can receive or send not only a text, but also binary objects using Java Serialization.

    When an EJB container decides to passivate (unload from memory) so-called stateful session bean, JVM persists its state in a safe place (usually on a disk). Later on, when this bean will be activated again, all its variables will be automatically deserialized by the EJB container.

    While it may not be too difficult for JVM to convert a primitive integer variable into four bytes for serialization, it's not as simple in case of classes containing variables with references to other objects. The process of converting such complex object into a sequence of bytes is called marshalling and the process of reconstructing of the objects from these bytes is called unmarshalling and Java does this job for you.

    Even though we have not learned yet how to create Web applications, I still want to mention that objects used for tracking of the user sessions should be serializable, otherwise you may not be able to deploy these application in a cluster of servers.

    Java serialization is a simple but powerful feature of the language, and you definitely will have a chance to use it in your applications.

  • More Stories By Yakov Fain

    Yakov Fain is a Java Champion and a co-founder of the IT consultancy Farata Systems and the product company SuranceBay. He wrote a thousand blogs (http://yakovfain.com) and several books about software development. Yakov authored and co-authored such books as "Angular 2 Development with TypeScript", "Java 24-Hour Trainer", and "Enterprise Web Development". His Twitter tag is @yfain

    Comments (9) View Comments

    Share your thoughts on this story.

    Add your comment
    You must be signed in to add a comment. Sign-in | Register

    In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.


    Most Recent Comments
    ndhai 06/17/08 09:17:58 AM EDT

    I have some pb with a test following:

    package com.lecam;

    import java.io.*;

    public class testFile implements java.io.Externalizable{

    byte one_byte = 1;
    int one_int = 1024;

    public testFile() {
    }

    public void writeExternal(ObjectOutput stream) throws java.io.IOException {
    stream.writeByte(one_byte);
    stream.writeInt(one_int);
    }

    public void readExternal(ObjectInput stream) throws java.io.IOException {
    one_byte = stream.readByte();
    one_int = stream.readInt();
    }

    public static void main(String args1[]) {
    System.out.print("Writing...");
    try {
    testFile SubFile = new testFile();
    FileOutputStream fos = new FileOutputStream("c:\\test.bin");
    ObjectOutputStream oos = new ObjectOutputStream(fos);
    SubFile.writeExternal(oos);
    oos.flush();
    oos.close();
    fos.close();
    } catch (java.io.IOException e) {
    e.printStackTrace();
    } catch(Exception e) {
    e.printStackTrace();
    }

    System.out.print("Reading...");
    try {
    FileInputStream fis = new FileInputStream("c:\\test.bin");
    ObjectInputStream ois = new ObjectInputStream(fis);
    testFile tFile = new testFile();
    tFile.readExternal(ois);
    System.out.println("SubFile : ");
    System.out.println("byte : "+(tFile.one_byte));
    System.out.println("int : "+ (tFile.one_int));
    ois.close();
    fis.close();
    } catch (java.io.IOException e) {
    e.printStackTrace();
    } catch(Exception e) {
    e.printStackTrace();
    }
    System.out.print("END...");
    }
    }

    question: the test.bin file should be 5 bytes (one byte + one int = 1 + 4 = 5 bytes)
    but it is 11 bytes! I don't know why!
    thanks

    Sreerag 08/07/07 01:47:30 PM EDT

    You have explained it in a simple, nice manner. Thanks a lot !

    Sreerag K M 08/07/07 01:45:49 PM EDT

    The presentation is so nice, simple. Thanks a lot

    Josh 04/14/04 05:25:12 PM EDT

    Ravi,

    If you serialize an externalizeable object, it''s readExternal or writeExternal methods will automatically get called. So, the scenario you mention should never happen. When you implement Externalizable, you take control of the serialization completely, so the transient modifier will not have an effect on fields in the Externalizable object.

    Ravi 04/14/04 03:19:03 PM EDT

    Excellent article. I had a concern with transient data serialization when we do a serialization with externalizable interface. I mean when I implement a class with externalizable and do a normal serialization without being used its readExternal or writeExternal calls, then the Transient data is still get serialized.
    Can anyone update me on this point?

    Josh 04/14/04 07:19:06 AM EDT

    Good article. As the previous comment indicates, using Java serialization can introduce some problems when the objects are read in by a different version of the software. I don''t recommend using Java serialization for ''durable'' persistence for this reason. Using Externalizable can help, but for complex applications this encourages the programmer to blend the persistence and other, unrelated aspects into the same object, which is not the best design. I would recommend delegating the Externalizable implementation into another object in this case.

    Mathieu 03/31/04 03:04:31 AM EST

    Very Good introductory material. However I would like to add a paragraph on class version management.
    Upon a change of the code of your class if you try to read an old serialized data, you may experience error. Externalize interface is for now the safe way to prevent yourself from that.

    java-user 03/29/04 11:15:31 AM EST

    Excellent article. Liked real-world experiences shared by author.

    andre 03/26/04 05:01:30 PM EST

    Awesome! Did not know about the alternative to Serializable which exposes your application.

    Latest Stories
    DX World EXPO, LLC, a Lighthouse Point, Florida-based startup trade show producer and the creator of "DXWorldEXPO® - Digital Transformation Conference & Expo" has announced its executive management team. The team is headed by Levent Selamoglu, who has been named CEO. "Now is the time for a truly global DX event, to bring together the leading minds from the technology world in a conversation about Digital Transformation," he said in making the announcement.
    "Space Monkey by Vivent Smart Home is a product that is a distributed cloud-based edge storage network. Vivent Smart Home, our parent company, is a smart home provider that places a lot of hard drives across homes in North America," explained JT Olds, Director of Engineering, and Brandon Crowfeather, Product Manager, at Vivint Smart Home, in this SYS-CON.tv interview at @ThingsExpo, held Oct 31 – Nov 2, 2017, at the Santa Clara Convention Center in Santa Clara, CA.
    SYS-CON Events announced today that Conference Guru has been named “Media Sponsor” of the 22nd International Cloud Expo, which will take place on June 5-7, 2018, at the Javits Center in New York, NY. A valuable conference experience generates new contacts, sales leads, potential strategic partners and potential investors; helps gather competitive intelligence and even provides inspiration for new products and services. Conference Guru works with conference organizers to pass great deals to gre...
    DevOps is under attack because developers don’t want to mess with infrastructure. They will happily own their code into production, but want to use platforms instead of raw automation. That’s changing the landscape that we understand as DevOps with both architecture concepts (CloudNative) and process redefinition (SRE). Rob Hirschfeld’s recent work in Kubernetes operations has led to the conclusion that containers and related platforms have changed the way we should be thinking about DevOps and...
    The Internet of Things will challenge the status quo of how IT and development organizations operate. Or will it? Certainly the fog layer of IoT requires special insights about data ontology, security and transactional integrity. But the developmental challenges are the same: People, Process and Platform. In his session at @ThingsExpo, Craig Sproule, CEO of Metavine, demonstrated how to move beyond today's coding paradigm and shared the must-have mindsets for removing complexity from the develop...
    In his Opening Keynote at 21st Cloud Expo, John Considine, General Manager of IBM Cloud Infrastructure, led attendees through the exciting evolution of the cloud. He looked at this major disruption from the perspective of technology, business models, and what this means for enterprises of all sizes. John Considine is General Manager of Cloud Infrastructure Services at IBM. In that role he is responsible for leading IBM’s public cloud infrastructure including strategy, development, and offering m...
    The next XaaS is CICDaaS. Why? Because CICD saves developers a huge amount of time. CD is an especially great option for projects that require multiple and frequent contributions to be integrated. But… securing CICD best practices is an emerging, essential, yet little understood practice for DevOps teams and their Cloud Service Providers. The only way to get CICD to work in a highly secure environment takes collaboration, patience and persistence. Building CICD in the cloud requires rigorous ar...
    Companies are harnessing data in ways we once associated with science fiction. Analysts have access to a plethora of visualization and reporting tools, but considering the vast amount of data businesses collect and limitations of CPUs, end users are forced to design their structures and systems with limitations. Until now. As the cloud toolkit to analyze data has evolved, GPUs have stepped in to massively parallel SQL, visualization and machine learning.
    "Evatronix provides design services to companies that need to integrate the IoT technology in their products but they don't necessarily have the expertise, knowledge and design team to do so," explained Adam Morawiec, VP of Business Development at Evatronix, in this SYS-CON.tv interview at @ThingsExpo, held Oct 31 – Nov 2, 2017, at the Santa Clara Convention Center in Santa Clara, CA.
    To get the most out of their data, successful companies are not focusing on queries and data lakes, they are actively integrating analytics into their operations with a data-first application development approach. Real-time adjustments to improve revenues, reduce costs, or mitigate risk rely on applications that minimize latency on a variety of data sources. In his session at @BigDataExpo, Jack Norris, Senior Vice President, Data and Applications at MapR Technologies, reviewed best practices to ...
    Widespread fragmentation is stalling the growth of the IIoT and making it difficult for partners to work together. The number of software platforms, apps, hardware and connectivity standards is creating paralysis among businesses that are afraid of being locked into a solution. EdgeX Foundry is unifying the community around a common IoT edge framework and an ecosystem of interoperable components.
    "ZeroStack is a startup in Silicon Valley. We're solving a very interesting problem around bringing public cloud convenience with private cloud control for enterprises and mid-size companies," explained Kamesh Pemmaraju, VP of Product Management at ZeroStack, in this SYS-CON.tv interview at 21st Cloud Expo, held Oct 31 – Nov 2, 2017, at the Santa Clara Convention Center in Santa Clara, CA.
    Large industrial manufacturing organizations are adopting the agile principles of cloud software companies. The industrial manufacturing development process has not scaled over time. Now that design CAD teams are geographically distributed, centralizing their work is key. With large multi-gigabyte projects, outdated tools have stifled industrial team agility, time-to-market milestones, and impacted P&L stakeholders.
    "Akvelon is a software development company and we also provide consultancy services to folks who are looking to scale or accelerate their engineering roadmaps," explained Jeremiah Mothersell, Marketing Manager at Akvelon, in this SYS-CON.tv interview at 21st Cloud Expo, held Oct 31 – Nov 2, 2017, at the Santa Clara Convention Center in Santa Clara, CA.
    Enterprises are adopting Kubernetes to accelerate the development and the delivery of cloud-native applications. However, sharing a Kubernetes cluster between members of the same team can be challenging. And, sharing clusters across multiple teams is even harder. Kubernetes offers several constructs to help implement segmentation and isolation. However, these primitives can be complex to understand and apply. As a result, it’s becoming common for enterprises to end up with several clusters. Thi...