Index: src/java/org/apache/lucene/index/Demo.java
===================================================================
--- src/java/org/apache/lucene/index/Demo.java	(revision 0)
+++ src/java/org/apache/lucene/index/Demo.java	(revision 0)
@@ -0,0 +1,91 @@
+package org.apache.lucene.index;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+
+import org.apache.lucene.util.CustomExternalizableReader;
+
+public class Demo {
+  public static void main(String[] args) throws Exception {
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    ObjectOutput out = new ObjectOutputStream(baos);
+
+    SomeClass c = new SomeClass();
+    c.setOne(1);
+    c.setTwo(2);
+    System.out.println("Serializing: ");
+    c.writeExternal(out);
+    out.flush();
+
+    byte[] data_old = baos.toByteArray();
+    readOld(data_old);
+
+    baos = new ByteArrayOutputStream();
+    out = new ObjectOutputStream(baos);
+
+    SomeClassNewVersion c_new = new SomeClassNewVersion();
+    c_new.setOne(1);
+    c_new.setTwo(2);
+    c_new.setThree(3);
+    c_new.writeExternal(out);
+    out.flush();
+
+    byte[] data_new = baos.toByteArray();
+
+    System.out.println("\nDeserializing with default reader: ");
+    readNew(data_old);
+    readNew(data_new);
+
+    // Now the user implements their own backwards compatible reader
+    SomeClassNewVersion.extReader = new CustomExternalizableReader() {
+      public void readExternal(Object obj, ObjectInput in) throws IOException,
+          ClassNotFoundException {
+        SomeClassNewVersion c_new = (SomeClassNewVersion) obj;
+        long uid = in.readLong();
+        int one = in.readInt();
+        int two = in.readInt();
+        int three;
+        if (uid == 1) {
+          // old version - initialze with default value
+          three = -3;
+        } else {
+          // new version
+          three = in.readInt();
+        }
+        c_new.init(one, two, three);
+      }
+    };
+
+    System.out
+        .println("\nDeserializing with custom (backwards-compatible) reader: ");
+    readNew(data_old);
+    readNew(data_new);
+  }
+
+  static void readOld(byte[] data) {
+    try {
+      ObjectInput in = new ObjectInputStream(new ByteArrayInputStream(data));
+      SomeClass c = new SomeClass();
+      c.readExternal(in);
+      System.out.println("\t" + c);
+    } catch (Exception e) {
+      System.out.println("\tERROR: " + e.getMessage());
+    }
+  }
+
+  static void readNew(byte[] data) {
+    try {
+      ObjectInput in = new ObjectInputStream(new ByteArrayInputStream(data));
+      SomeClassNewVersion c_new = new SomeClassNewVersion();
+      c_new.readExternal(in);
+      System.out.println("\t" + c_new);
+    } catch (Exception e) {
+      System.out.println("\tERROR: " + e.getMessage());
+    }
+  }
+}
Index: src/java/org/apache/lucene/index/SomeClass.java
===================================================================
--- src/java/org/apache/lucene/index/SomeClass.java	(revision 0)
+++ src/java/org/apache/lucene/index/SomeClass.java	(revision 0)
@@ -0,0 +1,70 @@
+package org.apache.lucene.index;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+import org.apache.lucene.util.CustomExternalizableReader;
+
+public class SomeClass implements Externalizable {
+  private int one;
+  private int two;
+
+  public int getOne() {
+    return one;
+  }
+
+  public void setOne(int one) {
+    this.one = one;
+  }
+
+  public int getTwo() {
+    return two;
+  }
+
+  public void setTwo(int two) {
+    this.two = two;
+  }
+
+  public String toString() {
+    return "SomeClass[one: " + one + ", two: " + two + "]";
+  }
+
+  /*
+   * The following code is for object externalization
+   */
+
+  static final long serialVersionUID = 1L;
+
+  public void readExternal(ObjectInput in) throws IOException,
+      ClassNotFoundException {
+    extReader.readExternal(this, in);
+  }
+
+  public void writeExternal(ObjectOutput out) throws IOException {
+    out.writeLong(serialVersionUID);
+    out.writeInt(one);
+    out.writeInt(two);
+  }
+
+  static CustomExternalizableReader extReader = new CustomExternalizableReader() {
+    public void readExternal(Object obj, ObjectInput in) throws IOException,
+        ClassNotFoundException {
+      SomeClass s = (SomeClass) obj;
+      long uid = in.readLong();
+      if (uid != serialVersionUID) {
+        throw new IOException("Wrong serialVerionUID: " + uid);
+      }
+      int one = in.readInt();
+      int two = in.readInt();
+      s.init(one, two);
+    }
+  };
+
+  // initialization method for readExternal
+  void init(int one, int two) {
+    this.one = one;
+    this.two = two;
+  }
+}
Index: src/java/org/apache/lucene/index/SomeClassNewVersion.java
===================================================================
--- src/java/org/apache/lucene/index/SomeClassNewVersion.java	(revision 0)
+++ src/java/org/apache/lucene/index/SomeClassNewVersion.java	(revision 0)
@@ -0,0 +1,93 @@
+package org.apache.lucene.index;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+import org.apache.lucene.util.CustomExternalizableReader;
+
+/**
+ * In the new version of this class we add a new variable 'three', increment the
+ * serialVersionUID and change the readExternal/writeExternal methods to
+ * read/write the new variable.
+ * 
+ */
+public class SomeClassNewVersion implements Externalizable {
+  private int one;
+  private int two;
+  private int three;
+
+  public int getOne() {
+    return one;
+  }
+
+  public void setOne(int one) {
+    this.one = one;
+  }
+
+  public int getTwo() {
+    return two;
+  }
+
+  public void setTwo(int two) {
+    this.two = two;
+  }
+
+  public int getThree() {
+    return three;
+  }
+
+  public void setThree(int three) {
+    this.three = three;
+  }
+
+  public String toString() {
+    return "SomeClassNewVersion[one: " + one + ", two: " + two + ", three: "
+        + three + "]";
+  }
+
+  /*
+   * The following code is for object externalization
+   */
+
+  static final long serialVersionUID = 2L;
+
+  public void readExternal(ObjectInput in) throws IOException,
+      ClassNotFoundException {
+    extReader.readExternal(this, in);
+  }
+
+  public void writeExternal(ObjectOutput out) throws IOException {
+    out.writeLong(serialVersionUID);
+    out.writeInt(one);
+    out.writeInt(two);
+    out.writeInt(three);
+  }
+
+  /**
+   * This reader can only read the externalized format created with the same
+   * version of this class. If backwards-compatibility is desired, a custom
+   * reader has to be implemented.
+   */
+  static CustomExternalizableReader extReader = new CustomExternalizableReader() {
+    public void readExternal(Object obj, ObjectInput in) throws IOException,
+        ClassNotFoundException {
+      SomeClassNewVersion s = (SomeClassNewVersion) obj;
+      long uid = in.readLong();
+      if (uid != serialVersionUID) {
+        throw new IOException("Wrong serialVerionUID: " + uid);
+      }
+      int one = in.readInt();
+      int two = in.readInt();
+      int three = in.readInt();
+      s.init(one, two, three);
+    }
+  };
+
+  void init(int one, int two, int three) {
+    this.one = one;
+    this.two = two;
+    this.three = three;
+  }
+}
Index: src/java/org/apache/lucene/util/CustomExternalizableReader.java
===================================================================
--- src/java/org/apache/lucene/util/CustomExternalizableReader.java	(revision 0)
+++ src/java/org/apache/lucene/util/CustomExternalizableReader.java	(revision 0)
@@ -0,0 +1,9 @@
+package org.apache.lucene.util;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+
+public abstract class CustomExternalizableReader {
+  public abstract void readExternal(Object obj, ObjectInput in)
+      throws IOException, ClassNotFoundException;
+}
