Java.next -- Four languages that represent the future of Java
Blogger Stuart Halloway has begun a series of posts on trends that point to the future of the Java platform. In his first post, he compares Clojure, Groovy, JRuby, and Scala -- four wildly different languages that nonetheless all play together in the JRE. Find out what unites these languages and what they can tell us about the future of Java-based development ...

Newsletter sign-up

Sign up for our technology specific newsletters.

Enterprise Java
View all newsletters

Email Address:

It's in the contract! Object versions for JavaBeans

Use object versioning to maintain serialization compatibility with your JavaBeans

Over the past two months, we've gone into some depth regarding how to serialize objects in Java. (See "Serialization and the JavaBeans Specification" and "Do it the `Nescafé' way -- with freeze-dried JavaBeans.") This month's article assumes you've either already read these articles or you understand the topics they cover. You should understand what serialization is, how to use the Serializable interface, and how to use the java.io.ObjectOutputStream and java.io.ObjectInputStream classes.

Why you need versioning

What a computer does is determined by its software, and software is extremely easy to change. This flexibility, usually considered an asset, has its liabilities. Sometimes it seems that software is too easy to change. You've undoubtedly run into at least one of the following situations:

  • A document file you received via e-mail won't read correctly in your word processor, because yours is an older version with an incompatible file format

  • A Web page operates differently on different browsers because different browser versions support different feature sets

  • An application won't run because you have the wrong version of a particular library

  • Your C++ won't compile because the header and source files are of incompatible versions



All of these situations are caused by incompatible versions of software and/or the data the software manipulates. Like buildings, personal philosophies, and riverbeds, programs change constantly in response to the changing conditions around them. (If you don't think buildings change, read Stewart Brand's outstanding book How Buildings Learn, a discussion of how structures transform over time. See Resources for more information.) Without a structure to control and manage this change, any software system of any useful size eventually degenerates into chaos. The goal in software versioning is to ensure that the version of software you are currently using produces correct results when it encounters data produced by other versions of itself.

This month, we're going to discuss how Java class versioning works, so that we can provide version control of our JavaBeans. The versioning structure for Java classes permits you to indicate to the serialization mechanism whether a particular data stream (that is, a serialized object) is readable by a particular version of a Java class. We'll talk about "compatible" and "incompatible" changes to classes, and why these changes affect versioning. We'll go over the goals of the versioning structure, and how the java.io package meets those goals. And, we'll learn to put safeguards into our code to ensure that when we read object streams of various versions, the data is always consistent after the object is read.

Version aversion

There are various kinds of versioning problems in software, all of which pertain to compatibility between chunks of data and/or executable code:

  • Differing versions of the same software may or may not be able to handle each others' data storage formats

  • Programs that load executable code at runtime must be able to identify the correct version of the software object, loadable library, or object file to do the job

  • A class's methods and fields must maintain the same meaning as the class evolves, or existing programs may break in places where those methods and fields are used

  • Source code, header files, documentation, and build scripts must all be coordinated in a software build environment to ensure that binary files are built from the correct versions of the source files



This article on Java object versioning only addresses the first three -- that is, version control of binary objects and their semantics in a runtime environment. (There's a vast array of software available for versioning source code, but we're not covering that here.)

It's important to remember that serialized Java object streams don't contain bytecodes. They contain only the information necessary to reconstruct an object assuming you have the class files available to build the object. But what happens if the class files of the two Java virtual machines (JVMs) (the writer and the reader) are of different versions? How do we know if they're compatible?

A class definition can be thought of as a "contract" between the class and the code that calls the class. This contract includes the class's API (application programming interface). Changing the API is equivalent to changing the contract. (Other changes to a class may also imply changes to the contract, as we'll see.) As a class evolves, it's important to maintain the behavior of previous versions of the class so as not to break the software in places that depended upon given behavior.

A version change example

Imagine you had a method called getItemCount() in a class, which meant get the total number of items this object contains, and this method was used in a dozen places throughout your system. Then, imagine at some later time that you change getItemCount() to mean get the maximum number of items this object has ever contained. Your software will most likely break in most places where this method was used, because suddenly the method will be reporting different information. Essentially, you've broken the contract; so it serves you right that your program now has bugs in it.

There's no way, short of disallowing changes altogether, to completely automate the detection of this sort of change, because it happens at the level of what a program means, not simply at the level of how that meaning is expressed. (If you do think of a way to do this easily and generally, you're going to be richer than Bill.) So, in the absence of a complete, general, and automated solution to this problem, what can we do to avoid getting into hot water when we change our classes (which, of course, we must)?

The easiest answer to this question is to say that if a class changes at all, it shouldn't be "trusted" to maintain the contract. After all, a programmer might have done anything to the class, and who knows if the class still works as advertised? This solves the problem of versioning, but it's an impractical solution because it's way too restrictive. If the class is modified to improve performance, say, there's no reason to disallow using the new version of the class simply because it doesn't match the old one. Any number of changes may be made to a class without breaking the contract.

Resources
  • The initial document that lays it on the line about compatibility between class file versions is the "Binary Compatibility" section of the Java Language Specification (JLS). This chapter of the JLS specifies all compatible changes to a class that every JVM file must support
    http://www.javasoft.com/docs/books/jls/html/13.doc.html
  • The complete list of compatible and incompatible changes can be found at http://www.javasoft.com/products/jdk/1.2/docs/gui
  • This is a part of the Java Object Serialization Specification, which appears at http://java.sun.com/products/jdk/1.1/docs/guide/serialization/spec/version.doc.html#6678
  • What do changing buildings have to do with software? Plenty! Software and buildings are both complex structures that must change to adapt to new uses and situations if they are to survive. Whereas most architecture books describe how they work in space, read How Buildings Learn, by Stewart Brand. He discusses how buildings work in time. There are many conceptual parallels to designing software for maintainability. http://www.amazon.com/exec/obidos/ISBN=0140139966/0898-3091519-778439
  • For a wild ride along the same lines of thought, check out A Big Ball of Mud, by Brian Foote and Joseph Yoder, at the Department of Computer Science, University of Illinois at Urbana-Champaign. http://laputa.isdn.uiuc.edu/mud/mud.html
  • You can download and print the National Institute of Standards and Technology's specification for the SHA-1 secure hash from http://www.itl.nist.gov/div897/pubs/fip180-1.htm
  • Previous JavaBeans columns: