Newsletter sign-up
View all newsletters

Sign up for our technology specific newsletters.

Enterprise Java
Email Address:

Serialization grab bag

Answers to reader questions about serialization

  • Digg
  • Reddit
  • SlashDot
  • Stumble
  • del.icio.us
  • Technorati
  • dzone
JavaWorld readers have responded to the past three months of JavaBeans columns with some interesting questions. This month, we'll go through a grab bag of serialization topics in response to these questions. We'll look into the details of initializing transient fields when a JavaBean (or any other object) is deserialized. We'll also revisit the writeObject() and readObject() methods, and look at a new example of how they may be used. And, we'll take a look at another feature of the Java Object Serialization Specification, object validation, which checks an object after deserialization to ensure that it's valid.

Deserialization and static initialization of transients

This month I received the following reader comment:

... transient initializers aren't instantiated during object deserialization; that is, if you have: transient int fred = 4;, you would expect that this value would not be serialized during the saving process (it doesn't) but that when deserializing, it would assume a default value of 4. However, it doesn't. It assumes a value of 0 because that's the default value for things of type int. I have found that the sensible solution to this plan is:
  1. Don't have any initializers in the class definition
  2. Have a method called init(), which sets up the default values
  3. Invoke init() after the constructor has been called


However, I have had a number of problems with this depending on how the invocation of the constructor has been called, and vice versa.

I would be interested to hear if you have any other ways of achieving this.



So, the complaint is that each transient variable in a deserialized object is initialized to the default value for its type, even if static initializers for those variables appear in the source file. I agree that this seems counterintuitive.

Even though transient variables are (by definition) not part of an object's state, it would be reasonable to expect that the class initializes them with the static initializer when the instance is created. But such is not the case. Transient variables are instantiated (despite what the letter says), but their static initializations are never applied during deserialization.

Let's explore this situation a bit further. We'll try to reproduce the problem by creating a serializable class containing a transient field, then serialize and deserialize it and see what results. Let's define a class called SerTest that contains an int instance field, a String instance field, and a private transient int instance field. Then, we'll put print() statements in the code at specific places to see what the variable values are.

Just for fun, we'll give SerTest a base class called SerTestBase, which is not serializable but which also contains a transient field. (You'll see why shortly.) SerTest's transient field has a static initializer expression that initializes it to 12, and SerTestBase statically initializes its transient to 99. Here's the source code for the test class and its main routine:

001 
002 import java.lang.*;
003 import java.io.*;
004 
005 // Note that the base class is not serializable
006 class SerTestBase extends java.lang.Object
007 {
008     private transient int iTransient_ = 99;
009 
010     public SerTestBase() {
011         System.out.println("Called SerTestBase no-arg constructor");
012     }
013 
014     public void print() {
015         System.out.println("Base: iTransient_ = " + iTransient_);
016     }
017 }
018 
019 // Serializable subclass
020 class SerTest extends SerTestBase implements java.io.Serializable {
021             
022     protected int a_ = 25;
023     protected String sTitle_ = new String("");
024     private transient int iNotSerialized_ = 12;
025 
026     public SerTest() {
027         System.out.println("Default constructor");
028         print();
029     }           
030 
031     public SerTest(int a, String s) {
032         System.out.println("2-arg constructor");
033         a_ = a;
034         sTitle_ = s;
035         print();
036    }
037 
038     // How to load myself from a stream
039     private void readObject(java.io.ObjectInputStream in)
040         throws IOException, ClassNotFoundException {
041     System.out.println("BEFORE READ");
042     print();
043         in.defaultReadObject();
044     System.out.println("AFTER READ");
045     print();
046     }
047 
048     public void print() {
049         super.print();
050         System.out.println("a=" + a_ + ", s=" + sTitle_ +
051             ", NotSerialized = " + iNotSerialized_);
052     }
053 
054     // How to write myself to a stream
055     private void writeObject(java.io.ObjectOutputStream out) 
056     throws IOException {
057         out.defaultWriteObject();
058     }
059 
060     // Properties
061     public void setTitle(String sTitle) { sTitle_ = sTitle; }
062     public String getTitle() { return sTitle_; }
063 
064     public void setA(int aa) { a_ = aa; }
065     public int getA() { return a_; }
066 };
067 
068 //
069 // main()
070 //
071 class Demo1 {
072 
073     private static void Usage() throws java.io.IOException {
074         System.out.println("Usage:\n\tDemo1 w file a string\n\tDemo1 r file");
075         IOException ex = new IOException("ERROR");
076         throw ex;
077     }
078 
079     public static void main(String[] args)
080     {
081         String cmd = args[0];
082 
083         try {
084             if (cmd.compareTo("w") == 0) {
085                 if (args.length != 4) { Usage(); }
086 
087                 int aa = Integer.parseInt(args[2]);
088                 String ss = args[3];
089 
090                 SerTest   bar = new SerTest(aa, ss);
091 
092                 FileOutputStream f = new FileOutputStream(args[1]);
093                 ObjectOutputStream s = new ObjectOutputStream(f);
094             
095                 System.out.println("Write: a=" + aa + ", s='" + ss + "'");
096 
097                 s.writeObject(bar);
098                 s.flush();
099             } else if (cmd.compareTo("r") == 0) {
100                 if (args.length != 2) { Usage(); }
101 
102                 FileInputStream f = new FileInputStream(args[1]);
103                 ObjectInputStream s = new ObjectInputStream(f);
104 
105                 System.out.println("Read SerTest:");
106 
107                 SerTest bar = (SerTest) s.readObject();
108 
109         System.out.println("RECEIVED OBJECT:");
110                 bar.print();
111             } else {
112                 System.err.println("Unknown command " + cmd);
113                 Usage();
114             }
115         }
116 
117         catch (Exception ex) {
118             System.out.println("Exception: " + ex.getMessage());
119             ex.printStackTrace();
120         }
121     }
122 };


The Demo1 class writes or reads a SerTest object to or from a disk file, and tells the object to print itself after construction. So, let's run it and see what happens. First, we tell the object to serialize; here's the result:

  • Digg
  • Reddit
  • SlashDot
  • Stumble
  • del.icio.us
  • Technorati
  • dzone
Comment
Login
Forgot your account info?
Add comment
Anonymous comments subject to approval. Register here for member benefits.
Have a JavaWorld account? Log in here. Register now for a free account.
Resources
  • The Java Object Serialization Specification, which describes serialization, appears at http://www.javasoft.com/products/jdk/1.2/docs/guide/serialization/spec/serialTOC.doc.html.
  • Be sure to check the outstanding "Java Gotchas" page, by Roedy Green at http://oberon.ark.com/~roedy/gotchas.html. This page covers not only problems with object deserialization, but many other possible pitfalls in Java, or differences from C/C++, that might tend to confuse and frustrate you, even if you're not aware of them. (This page features has a cool "creamsicle" color scheme.)
  • Richard Baldwin's postmodern "Java Programming Tutorials" site contains Java tutorials on serialization (in the Advanced Java Programming Tutorial section) and many, many other topics. This is one hot site. Find it at http://www.phrantic.com/scoop/onjava.html.
  • You can download the source for the examples in this article:
  • in Unix tar format http://www.javaworld.com/javaworld/jw-04-1998/beans/beans.tar
  • in Windows ZIP format http://www.javaworld.com/javaworld/jw-04-1998/beans/beans.zip