ObjectStreamClass: Peeking at a Java Object’s Serialization

ObjectStreamClass can be a useful class to analyze the serialization characteristics of a serialized class loaded in the JVM. This post looks at some of the information this class provides about a loaded serialized class.

ObjectStreamClass provides two static methods for lookup of a class: lookup(class) and lookupAny(Class). The first, lookup(Class), will only return an instance of ObjectStreamClass when the provided class is serializable and returns null if the provided class is not serializable. The second, lookupAny(Class) returns an instance of ObjectStreamClass for the provided class regardless of whether it’s serializable or not.

Once an instance of ObjectStreamClass is provided via the static “lookup” methods, that instance can be queried for class name, for serial version UID, and for serializable fields.

To demonstrate use of ObjectStreamClass, I first list the code listings for two simple classes that will be part of the demonstration. One class, Person, is Serializable, but has a transient field. The other class, UnserializablePerson, is nearly identical, but it is not Serializable.

Person.java

package dustin.examples.serialization;

import java.io.Serializable;

/**
 * Person class intended for demonstration of ObjectStreamClass.
 * 
 * @author Dustin
 */
public class Person implements Serializable
{
   private final String lastName;
   private final String firstName;
   transient private final String fullName;

   public Person(final String newLastName, final String newFirstName)
   {
      this.lastName = newLastName;
      this.firstName = newFirstName;
      this.fullName = this.firstName + " " + this.lastName;
   }

   public String getFirstName()
   {
      return this.firstName;
   }

   public String getLastName()
   {
      return this.lastName;
   }

   public String getFullName()
   {
      return this.fullName;
   }

   @Override
   public String toString()
   {
      return this.fullName;
   }
}

UnserializablePerson.java

package dustin.examples.serialization;

/**
 * Person class intended for demonstration of ObjectStreamClass.
 * 
 * @author Dustin
 */
public class UnserializablePerson
{
   private final String lastName;
   private final String firstName;
   private final String fullName;

   public UnserializablePerson(final String newLastName, final String newFirstName)
   {
      this.lastName = newLastName;
      this.firstName = newFirstName;
      this.fullName = this.firstName + " " + this.lastName;
   }

   public String getFirstName()
   {
      return this.firstName;
   }

   public String getLastName()
   {
      return this.lastName;
   }

   public String getFullName()
   {
      return this.fullName;
   }

   @Override
   public String toString()
   {
      return this.fullName;
   }
}

With two classes in place to run use in conjunction with ObjectStreamClass, it’s now time to look at a simple demonstration application that shows use of ObjectStreamClass.

ObjectStreamClassDemo.java

package dustin.examples.serialization;

import static java.lang.System.out;

import java.io.ObjectStreamClass;
import java.io.ObjectStreamField;

/**
 * Demonstrates use of ObjectStreamDemo.
 * 
 * @author Dustin
 */
public class ObjectStreamClassDemo
{
   /**
    * Displays class name, serial version UID, and serializable fields as
    * indicated by the provided instance of ObjectStreamClass.
    * 
    * @param serializedClass 
    */
   public static void displaySerializedClassInformation(
      final ObjectStreamClass serializedClass)
   {
      final String serializedClassName = serializedClass.getName();
      out.println("Class Name: " + serializedClassName);
      final long serializedVersionUid = serializedClass.getSerialVersionUID();
      out.println("serialversionuid: " + serializedVersionUid);
      final ObjectStreamField[] fields = serializedClass.getFields();
      out.println("Serialized Fields:");
      for (final ObjectStreamField field : fields)
      {
         out.println("\t" + field.getTypeString() + " " + field.getName());
      }
   }

   /**
    * Main function that demonstrates use of ObjectStreamDemo.
    * 
    * @param arguments Command line arguments; none expected.
    */
   public static void main(String[] arguments)
   {
      // Example 1: ObjectStreamClass.lookup(Class) on a Serializable class
      out.println("\n=== ObjectStreamClass.lookup(Serializable) ===");
      final ObjectStreamClass serializedClass = ObjectStreamClass.lookup(Person.class);
      displaySerializedClassInformation(serializedClass);

      // Example 2: ObjectStreamClass.lookup(Class) on a class that is not
      //            Serializable (which will result in a NullPointerException
      //            when trying to access null returned from 'lookup'
      out.println("\n=== ObjectStreamClass.lookup(Unserializable) ===");
      try
      {
         final ObjectStreamClass unserializedClass =
            ObjectStreamClass.lookup(UnserializablePerson.class);
         displaySerializedClassInformation(unserializedClass);
      }
      catch (NullPointerException npe)
      {
         out.println("NullPointerException: Unable to lookup unserializable class with ObjectStreamClass.lookup.");
      }

      // Example 3: ObjectStreamClass.lookupAny(Class) works without the
      //            NullPointerException, but only provides name of the class as
      //            Serial Version UID and serialized fields do not apply in the
      //            case of a class that is not serializable.
      out.println("\n=== ObjectStreamClass.lookupAny(Unserializable) ===");
      final ObjectStreamClass unserializedClass =
          ObjectStreamClass.lookupAny(UnserializablePerson.class);
      displaySerializedClassInformation(unserializedClass);
   }
}

The comments in the source code above indicate what is being demonstrated. The output from running this class is shown in the next screen snapshot.

outputObjectStreamClassDemo

When the output shown above is correlated with the code before it, we can make several observations related to ObjectStreamClass. These include the fact that the transient field of a serializable class is not returned as one of the serializable fields. We also see that ObjectStreamClass.lookup(Class) method returns null if the class provided to it is not serializable. ObjectStreamClass.lookupAny(Class) returns an instance of ObjectStreamClass for classes that are not serializable, but only the class’s name is available in that case.

The code above showed a Serial Version UID for Person.java of 1940442894442614965. When serialver is run on the command line, the same Serial Version UID is generated and displayed.

serialverOnPersonPowerShell

What’s nice about the ability to programatically calculate the same Serial Version UID as would be calculated by the serialver tool that comes with the Oracle JDK is that one could explicitly add the same Serial Version UID to generated code as would be implicitly added anyway. Any JVM-friendly script or tool (such as one written in Groovy) that needs to know the implicit Serial Version UID of a class could use ObjectStreamClass to obtain that Serial Version UID.
 

Related Whitepaper:

Bulletproof Java Code: A Practical Strategy for Developing Functional, Reliable, and Secure Java Code

Use Java? If you do, you know that Java software can be used to drive application logic of Web services or Web applications. Perhaps you use it for desktop applications? Or, embedded devices? Whatever your use of Java code, functional errors are the enemy!

To combat this enemy, your team might already perform functional testing. Even so, you're taking significant risks if you have not yet implemented a comprehensive team-wide quality management strategy. Such a strategy alleviates reliability, security, and performance problems to ensure that your code is free of functionality errors.Read this article to learn about this simple four-step strategy that is proven to make Java code more reliable, more secure, and easier to maintain.

Get it Now!  

Leave a Reply


8 − eight =



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.

Sign up for our Newsletter

20,709 insiders are already enjoying weekly updates and complimentary whitepapers! Join them now to gain exclusive access to the latest news in the Java world, as well as insights about Android, Scala, Groovy and other related technologies.

As an extra bonus, by joining you will get our brand new e-books, published by Java Code Geeks and their JCG partners for your reading pleasure! Enter your info and stay on top of things,

  • Fresh trends
  • Cases and examples
  • Research and insights
  • Two complimentary e-books