You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@avro.apache.org by cu...@apache.org on 2014/10/03 23:24:48 UTC

svn commit: r1629326 - in /avro/trunk: ./ lang/java/avro/src/main/java/org/apache/avro/specific/ lang/java/avro/src/test/java/org/apache/avro/ lang/java/avro/src/test/java/org/apache/avro/specific/ lang/java/compiler/src/main/java/org/apache/avro/compi...

Author: cutting
Date: Fri Oct  3 21:24:48 2014
New Revision: 1629326

URL: http://svn.apache.org/r1629326
Log:
AVRO-1502. Java: Generated classes now implement Serializable.

Added:
    avro/trunk/lang/java/avro/src/main/java/org/apache/avro/specific/ExternalizableInput.java   (with props)
    avro/trunk/lang/java/avro/src/main/java/org/apache/avro/specific/ExternalizableOutput.java   (with props)
Modified:
    avro/trunk/CHANGES.txt
    avro/trunk/lang/java/avro/src/main/java/org/apache/avro/specific/SpecificData.java
    avro/trunk/lang/java/avro/src/main/java/org/apache/avro/specific/SpecificExceptionBase.java
    avro/trunk/lang/java/avro/src/main/java/org/apache/avro/specific/SpecificFixed.java
    avro/trunk/lang/java/avro/src/main/java/org/apache/avro/specific/SpecificRecordBase.java
    avro/trunk/lang/java/avro/src/test/java/org/apache/avro/FooBarSpecificRecord.java
    avro/trunk/lang/java/avro/src/test/java/org/apache/avro/TypeEnum.java
    avro/trunk/lang/java/avro/src/test/java/org/apache/avro/specific/TestSpecificData.java
    avro/trunk/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java
    avro/trunk/lang/java/compiler/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/fixed.vm
    avro/trunk/lang/java/compiler/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/record.vm
    avro/trunk/lang/java/ipc/src/test/java/org/apache/avro/specific/TestSpecificData.java
    avro/trunk/lang/java/tools/src/test/compiler/output-string/avro/examples/baseball/Player.java
    avro/trunk/lang/java/tools/src/test/compiler/output/Player.java

Modified: avro/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/avro/trunk/CHANGES.txt?rev=1629326&r1=1629325&r2=1629326&view=diff
==============================================================================
--- avro/trunk/CHANGES.txt (original)
+++ avro/trunk/CHANGES.txt Fri Oct  3 21:24:48 2014
@@ -21,6 +21,8 @@ Trunk (not yet released)
     and shortname matches when fullname matching fails.
     (Ryan Blue via cutting)
 
+    AVRO-1502. Java: Generated classes now implement Serializable. (cutting)
+
   OPTIMIZATIONS
 
   IMPROVEMENTS

Added: avro/trunk/lang/java/avro/src/main/java/org/apache/avro/specific/ExternalizableInput.java
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/avro/src/main/java/org/apache/avro/specific/ExternalizableInput.java?rev=1629326&view=auto
==============================================================================
--- avro/trunk/lang/java/avro/src/main/java/org/apache/avro/specific/ExternalizableInput.java (added)
+++ avro/trunk/lang/java/avro/src/main/java/org/apache/avro/specific/ExternalizableInput.java Fri Oct  3 21:24:48 2014
@@ -0,0 +1,50 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.avro.specific;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.ObjectInput;
+
+/** Helper to permit Externalizeable implementations that write to an
+ * InputStream. */
+class ExternalizableInput extends InputStream {
+  private final ObjectInput in;
+
+  public ExternalizableInput(ObjectInput in) { this.in = in; }
+
+  @Override public int available() throws IOException { return in.available(); }
+
+  @Override public void close() throws IOException { in.close(); }
+
+  @Override public boolean  markSupported() { return false; }
+
+  @Override public int read() throws IOException { return in.read(); }
+
+  @Override public int read(byte[] b) throws IOException { return in.read(b); }
+
+  @Override
+  public int read(byte[] b, int offset, int len) throws IOException {
+    return in.read(b, offset, len);
+  }
+  @Override
+  public long skip(long n) throws IOException {
+    return in.skip(n);
+  }
+}

Propchange: avro/trunk/lang/java/avro/src/main/java/org/apache/avro/specific/ExternalizableInput.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: avro/trunk/lang/java/avro/src/main/java/org/apache/avro/specific/ExternalizableOutput.java
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/avro/src/main/java/org/apache/avro/specific/ExternalizableOutput.java?rev=1629326&view=auto
==============================================================================
--- avro/trunk/lang/java/avro/src/main/java/org/apache/avro/specific/ExternalizableOutput.java (added)
+++ avro/trunk/lang/java/avro/src/main/java/org/apache/avro/specific/ExternalizableOutput.java Fri Oct  3 21:24:48 2014
@@ -0,0 +1,44 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.avro.specific;
+
+import java.io.OutputStream;
+import java.io.IOException;
+import java.io.ObjectOutput;
+
+/** Helper to permit Externalizeable implementations that write to an
+ * OutputStream. */
+class ExternalizableOutput extends OutputStream {
+  private final ObjectOutput out;
+
+  public ExternalizableOutput(ObjectOutput out) { this.out = out; }
+
+  @Override public void flush() throws IOException { out.flush(); }
+
+  @Override public void close() throws IOException { out.close(); }
+
+  @Override public void write(int c) throws IOException { out.write(c); }
+
+  @Override public void write(byte[] b) throws IOException { out.write(b); }
+
+  @Override
+  public void write(byte[] b, int offset, int len) throws IOException {
+    out.write(b, offset, len);
+  }
+}

Propchange: avro/trunk/lang/java/avro/src/main/java/org/apache/avro/specific/ExternalizableOutput.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: avro/trunk/lang/java/avro/src/main/java/org/apache/avro/specific/SpecificData.java
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/avro/src/main/java/org/apache/avro/specific/SpecificData.java?rev=1629326&r1=1629325&r2=1629326&view=diff
==============================================================================
--- avro/trunk/lang/java/avro/src/main/java/org/apache/avro/specific/SpecificData.java (original)
+++ avro/trunk/lang/java/avro/src/main/java/org/apache/avro/specific/SpecificData.java Fri Oct  3 21:24:48 2014
@@ -28,6 +28,8 @@ import java.util.LinkedHashMap;
 import java.nio.ByteBuffer;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.ParameterizedType;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
 
 import org.apache.avro.Schema;
 import org.apache.avro.Protocol;
@@ -38,6 +40,10 @@ import org.apache.avro.util.ClassUtils;
 import org.apache.avro.generic.GenericData;
 import org.apache.avro.io.DatumReader;
 import org.apache.avro.io.DatumWriter;
+import org.apache.avro.io.EncoderFactory;
+import org.apache.avro.io.BinaryEncoder;
+import org.apache.avro.io.DecoderFactory;
+import org.apache.avro.io.BinaryDecoder;
 
 /** Utilities for generated Java classes and interfaces. */
 public class SpecificData extends GenericData {
@@ -337,5 +343,16 @@ public class SpecificData extends Generi
    * @see #newInstance
    */
   public interface SchemaConstructable {}
-  
+
+  /** Runtime utility used by generated classes. */
+  public static BinaryDecoder getDecoder(ObjectInput in) {
+    return DecoderFactory.get()
+      .directBinaryDecoder(new ExternalizableInput(in), null);
+  }
+  /** Runtime utility used by generated classes. */
+  public static BinaryEncoder getEncoder(ObjectOutput out) {
+    return EncoderFactory.get()
+      .directBinaryEncoder(new ExternalizableOutput(out), null);
+  }
+
 }

Modified: avro/trunk/lang/java/avro/src/main/java/org/apache/avro/specific/SpecificExceptionBase.java
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/avro/src/main/java/org/apache/avro/specific/SpecificExceptionBase.java?rev=1629326&r1=1629325&r2=1629326&view=diff
==============================================================================
--- avro/trunk/lang/java/avro/src/main/java/org/apache/avro/specific/SpecificExceptionBase.java (original)
+++ avro/trunk/lang/java/avro/src/main/java/org/apache/avro/specific/SpecificExceptionBase.java Fri Oct  3 21:24:48 2014
@@ -18,12 +18,17 @@
 
 package org.apache.avro.specific;
 
+import java.io.Externalizable;
+import java.io.ObjectOutput;
+import java.io.ObjectInput;
+import java.io.IOException;
+
 import org.apache.avro.AvroRemoteException;
 import org.apache.avro.Schema;
 
 /** Base class for specific exceptions. */
 public abstract class SpecificExceptionBase extends AvroRemoteException
-  implements SpecificRecord {
+  implements SpecificRecord, Externalizable {
 
   public SpecificExceptionBase() {
     super();
@@ -56,5 +61,9 @@ public abstract class SpecificExceptionB
     return SpecificData.get().hashCode(this, this.getSchema());
   }
 
-}
+  @Override public abstract void writeExternal(ObjectOutput out)
+    throws IOException;
+  @Override public abstract void readExternal(ObjectInput in)
+    throws IOException;
 
+}

Modified: avro/trunk/lang/java/avro/src/main/java/org/apache/avro/specific/SpecificFixed.java
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/avro/src/main/java/org/apache/avro/specific/SpecificFixed.java?rev=1629326&r1=1629325&r2=1629326&view=diff
==============================================================================
--- avro/trunk/lang/java/avro/src/main/java/org/apache/avro/specific/SpecificFixed.java (original)
+++ avro/trunk/lang/java/avro/src/main/java/org/apache/avro/specific/SpecificFixed.java Fri Oct  3 21:24:48 2014
@@ -17,17 +17,53 @@
  */
 package org.apache.avro.specific;
 
-import org.apache.avro.generic.GenericData;
+import java.io.Externalizable;
+import java.io.ObjectOutput;
+import java.io.ObjectInput;
+import java.io.IOException;
+import java.util.Arrays;
+import org.apache.avro.Schema;
+import org.apache.avro.generic.GenericFixed;
+import org.apache.avro.io.BinaryData;
 
 /** Base class for generated fixed-sized data classes. */
-public abstract class SpecificFixed extends GenericData.Fixed {
+public abstract class SpecificFixed
+  implements GenericFixed, Comparable<SpecificFixed>, Externalizable {
+
+  private byte[] bytes;
+
   public SpecificFixed() {
-    setSchema(SpecificData.get().getSchema(getClass()));
+    bytes(new byte[getSchema().getFixedSize()]);
   }
   
   public SpecificFixed(byte[] bytes) {
-    this();
     bytes(bytes); 
   }
+
+  public void bytes(byte[] bytes) { this.bytes = bytes; }
+
+  @Override public byte[] bytes() { return bytes; }
+
+  @Override public abstract Schema getSchema();
+
+  @Override public boolean equals(Object o) {
+    if (o == this) return true;
+    return o instanceof GenericFixed
+      && Arrays.equals(bytes, ((GenericFixed)o).bytes());
+  }
+
+  @Override public int hashCode() { return Arrays.hashCode(bytes); }
+  @Override public String toString() { return Arrays.toString(bytes); }
+
+  @Override public int compareTo(SpecificFixed that) {
+    return BinaryData.compareBytes(this.bytes, 0, this.bytes.length,
+                                   that.bytes, 0, that.bytes.length);
+  }
+
+  @Override public abstract void writeExternal(ObjectOutput out)
+    throws IOException;
+  @Override public abstract void readExternal(ObjectInput in)
+    throws IOException;
+
 }
 

Modified: avro/trunk/lang/java/avro/src/main/java/org/apache/avro/specific/SpecificRecordBase.java
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/avro/src/main/java/org/apache/avro/specific/SpecificRecordBase.java?rev=1629326&r1=1629325&r2=1629326&view=diff
==============================================================================
--- avro/trunk/lang/java/avro/src/main/java/org/apache/avro/specific/SpecificRecordBase.java (original)
+++ avro/trunk/lang/java/avro/src/main/java/org/apache/avro/specific/SpecificRecordBase.java Fri Oct  3 21:24:48 2014
@@ -17,12 +17,18 @@
  */
 package org.apache.avro.specific;
 
+import java.io.Externalizable;
+import java.io.ObjectOutput;
+import java.io.ObjectInput;
+import java.io.IOException;
+
 import org.apache.avro.Schema;
 import org.apache.avro.generic.GenericRecord;
 
 /** Base class for generated record classes. */
 public abstract class SpecificRecordBase
-  implements SpecificRecord, Comparable<SpecificRecord>, GenericRecord {
+  implements SpecificRecord, Comparable<SpecificRecord>, GenericRecord,
+             Externalizable {
 
   public abstract Schema getSchema();
   public abstract Object get(int field);
@@ -61,5 +67,8 @@ public abstract class SpecificRecordBase
     return SpecificData.get().toString(this);
   }
 
+  @Override public abstract void writeExternal(ObjectOutput out)
+    throws IOException;
+  @Override public abstract void readExternal(ObjectInput in)
+    throws IOException;
 }
-

Modified: avro/trunk/lang/java/avro/src/test/java/org/apache/avro/FooBarSpecificRecord.java
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/avro/src/test/java/org/apache/avro/FooBarSpecificRecord.java?rev=1629326&r1=1629325&r2=1629326&view=diff
==============================================================================
--- avro/trunk/lang/java/avro/src/test/java/org/apache/avro/FooBarSpecificRecord.java (original)
+++ avro/trunk/lang/java/avro/src/test/java/org/apache/avro/FooBarSpecificRecord.java Fri Oct  3 21:24:48 2014
@@ -5,22 +5,31 @@
  */
 package org.apache.avro;  
 @SuppressWarnings("all")
+@org.apache.avro.specific.AvroGenerated
 public class FooBarSpecificRecord extends org.apache.avro.specific.SpecificRecordBase implements org.apache.avro.specific.SpecificRecord {
-  public static final org.apache.avro.Schema SCHEMA$ = new org.apache.avro.Schema.Parser().parse("{\"type\":\"record\",\"name\":\"FooBarSpecificRecord\",\"namespace\":\"org.apache.avro\",\"fields\":[{\"name\":\"id\",\"type\":\"int\"},{\"name\":\"relatedids\",\"type\":{\"type\":\"array\",\"items\":\"int\"}},{\"name\":\"typeEnum\",\"type\":[\"null\",{\"type\":\"enum\",\"name\":\"TypeEnum\",\"symbols\":[\"a\",\"b\",\"c\"]}],\"default\":null}]}");
+  private static final long serialVersionUID = 1031933828916876443L;
+  public static final org.apache.avro.Schema SCHEMA$ = new org.apache.avro.Schema.Parser().parse("{\"type\":\"record\",\"name\":\"FooBarSpecificRecord\",\"namespace\":\"org.apache.avro\",\"fields\":[{\"name\":\"id\",\"type\":\"int\"},{\"name\":\"name\",\"type\":{\"type\":\"string\",\"avro.java.string\":\"String\"}},{\"name\":\"nicknames\",\"type\":{\"type\":\"array\",\"items\":{\"type\":\"string\",\"avro.java.string\":\"String\"}}},{\"name\":\"relatedids\",\"type\":{\"type\":\"array\",\"items\":\"int\"}},{\"name\":\"typeEnum\",\"type\":[\"null\",{\"type\":\"enum\",\"name\":\"TypeEnum\",\"symbols\":[\"a\",\"b\",\"c\"]}],\"default\":null}]}");
+  public static org.apache.avro.Schema getClassSchema() { return SCHEMA$; }
   @Deprecated public int id;
+  @Deprecated public java.lang.String name;
+  @Deprecated public java.util.List<java.lang.String> nicknames;
   @Deprecated public java.util.List<java.lang.Integer> relatedids;
   @Deprecated public org.apache.avro.TypeEnum typeEnum;
 
   /**
-   * Default constructor.
+   * Default constructor.  Note that this does not initialize fields
+   * to their default values from the schema.  If that is desired then
+   * one should use <code>newBuilder()</code>. 
    */
   public FooBarSpecificRecord() {}
 
   /**
    * All-args constructor.
    */
-  public FooBarSpecificRecord(java.lang.Integer id, java.util.List<java.lang.Integer> relatedids, org.apache.avro.TypeEnum typeEnum) {
+  public FooBarSpecificRecord(java.lang.Integer id, java.lang.String name, java.util.List<java.lang.String> nicknames, java.util.List<java.lang.Integer> relatedids, org.apache.avro.TypeEnum typeEnum) {
     this.id = id;
+    this.name = name;
+    this.nicknames = nicknames;
     this.relatedids = relatedids;
     this.typeEnum = typeEnum;
   }
@@ -30,8 +39,10 @@ public class FooBarSpecificRecord extend
   public java.lang.Object get(int field$) {
     switch (field$) {
     case 0: return id;
-    case 1: return relatedids;
-    case 2: return typeEnum;
+    case 1: return name;
+    case 2: return nicknames;
+    case 3: return relatedids;
+    case 4: return typeEnum;
     default: throw new org.apache.avro.AvroRuntimeException("Bad index");
     }
   }
@@ -40,8 +51,10 @@ public class FooBarSpecificRecord extend
   public void put(int field$, java.lang.Object value$) {
     switch (field$) {
     case 0: id = (java.lang.Integer)value$; break;
-    case 1: relatedids = (java.util.List<java.lang.Integer>)value$; break;
-    case 2: typeEnum = (org.apache.avro.TypeEnum)value$; break;
+    case 1: name = (java.lang.String)value$; break;
+    case 2: nicknames = (java.util.List<java.lang.String>)value$; break;
+    case 3: relatedids = (java.util.List<java.lang.Integer>)value$; break;
+    case 4: typeEnum = (org.apache.avro.TypeEnum)value$; break;
     default: throw new org.apache.avro.AvroRuntimeException("Bad index");
     }
   }
@@ -62,6 +75,36 @@ public class FooBarSpecificRecord extend
   }
 
   /**
+   * Gets the value of the 'name' field.
+   */
+  public java.lang.String getName() {
+    return name;
+  }
+
+  /**
+   * Sets the value of the 'name' field.
+   * @param value the value to set.
+   */
+  public void setName(java.lang.String value) {
+    this.name = value;
+  }
+
+  /**
+   * Gets the value of the 'nicknames' field.
+   */
+  public java.util.List<java.lang.String> getNicknames() {
+    return nicknames;
+  }
+
+  /**
+   * Sets the value of the 'nicknames' field.
+   * @param value the value to set.
+   */
+  public void setNicknames(java.util.List<java.lang.String> value) {
+    this.nicknames = value;
+  }
+
+  /**
    * Gets the value of the 'relatedids' field.
    */
   public java.util.List<java.lang.Integer> getRelatedids() {
@@ -113,6 +156,8 @@ public class FooBarSpecificRecord extend
     implements org.apache.avro.data.RecordBuilder<FooBarSpecificRecord> {
 
     private int id;
+    private java.lang.String name;
+    private java.util.List<java.lang.String> nicknames;
     private java.util.List<java.lang.Integer> relatedids;
     private org.apache.avro.TypeEnum typeEnum;
 
@@ -124,23 +169,51 @@ public class FooBarSpecificRecord extend
     /** Creates a Builder by copying an existing Builder */
     private Builder(org.apache.avro.FooBarSpecificRecord.Builder other) {
       super(other);
+      if (isValidValue(fields()[0], other.id)) {
+        this.id = data().deepCopy(fields()[0].schema(), other.id);
+        fieldSetFlags()[0] = true;
+      }
+      if (isValidValue(fields()[1], other.name)) {
+        this.name = data().deepCopy(fields()[1].schema(), other.name);
+        fieldSetFlags()[1] = true;
+      }
+      if (isValidValue(fields()[2], other.nicknames)) {
+        this.nicknames = data().deepCopy(fields()[2].schema(), other.nicknames);
+        fieldSetFlags()[2] = true;
+      }
+      if (isValidValue(fields()[3], other.relatedids)) {
+        this.relatedids = data().deepCopy(fields()[3].schema(), other.relatedids);
+        fieldSetFlags()[3] = true;
+      }
+      if (isValidValue(fields()[4], other.typeEnum)) {
+        this.typeEnum = data().deepCopy(fields()[4].schema(), other.typeEnum);
+        fieldSetFlags()[4] = true;
+      }
     }
     
     /** Creates a Builder by copying an existing FooBarSpecificRecord instance */
     private Builder(org.apache.avro.FooBarSpecificRecord other) {
             super(org.apache.avro.FooBarSpecificRecord.SCHEMA$);
       if (isValidValue(fields()[0], other.id)) {
-        this.id = (java.lang.Integer) data().deepCopy(fields()[0].schema(), other.id);
+        this.id = data().deepCopy(fields()[0].schema(), other.id);
         fieldSetFlags()[0] = true;
       }
-      if (isValidValue(fields()[1], other.relatedids)) {
-        this.relatedids = (java.util.List<java.lang.Integer>) data().deepCopy(fields()[1].schema(), other.relatedids);
+      if (isValidValue(fields()[1], other.name)) {
+        this.name = data().deepCopy(fields()[1].schema(), other.name);
         fieldSetFlags()[1] = true;
       }
-      if (isValidValue(fields()[2], other.typeEnum)) {
-        this.typeEnum = (org.apache.avro.TypeEnum) data().deepCopy(fields()[2].schema(), other.typeEnum);
+      if (isValidValue(fields()[2], other.nicknames)) {
+        this.nicknames = data().deepCopy(fields()[2].schema(), other.nicknames);
         fieldSetFlags()[2] = true;
-    }
+      }
+      if (isValidValue(fields()[3], other.relatedids)) {
+        this.relatedids = data().deepCopy(fields()[3].schema(), other.relatedids);
+        fieldSetFlags()[3] = true;
+      }
+      if (isValidValue(fields()[4], other.typeEnum)) {
+        this.typeEnum = data().deepCopy(fields()[4].schema(), other.typeEnum);
+        fieldSetFlags()[4] = true;
+      }
     }
 
     /** Gets the value of the 'id' field */
@@ -167,6 +240,56 @@ public class FooBarSpecificRecord extend
       return this;
     }
 
+    /** Gets the value of the 'name' field */
+    public java.lang.String getName() {
+      return name;
+    }
+    
+    /** Sets the value of the 'name' field */
+    public org.apache.avro.FooBarSpecificRecord.Builder setName(java.lang.String value) {
+      validate(fields()[1], value);
+      this.name = value;
+      fieldSetFlags()[1] = true;
+      return this; 
+    }
+    
+    /** Checks whether the 'name' field has been set */
+    public boolean hasName() {
+      return fieldSetFlags()[1];
+    }
+    
+    /** Clears the value of the 'name' field */
+    public org.apache.avro.FooBarSpecificRecord.Builder clearName() {
+      name = null;
+      fieldSetFlags()[1] = false;
+      return this;
+    }
+
+    /** Gets the value of the 'nicknames' field */
+    public java.util.List<java.lang.String> getNicknames() {
+      return nicknames;
+    }
+    
+    /** Sets the value of the 'nicknames' field */
+    public org.apache.avro.FooBarSpecificRecord.Builder setNicknames(java.util.List<java.lang.String> value) {
+      validate(fields()[2], value);
+      this.nicknames = value;
+      fieldSetFlags()[2] = true;
+      return this; 
+    }
+    
+    /** Checks whether the 'nicknames' field has been set */
+    public boolean hasNicknames() {
+      return fieldSetFlags()[2];
+    }
+    
+    /** Clears the value of the 'nicknames' field */
+    public org.apache.avro.FooBarSpecificRecord.Builder clearNicknames() {
+      nicknames = null;
+      fieldSetFlags()[2] = false;
+      return this;
+    }
+
     /** Gets the value of the 'relatedids' field */
     public java.util.List<java.lang.Integer> getRelatedids() {
       return relatedids;
@@ -174,21 +297,21 @@ public class FooBarSpecificRecord extend
     
     /** Sets the value of the 'relatedids' field */
     public org.apache.avro.FooBarSpecificRecord.Builder setRelatedids(java.util.List<java.lang.Integer> value) {
-      validate(fields()[1], value);
+      validate(fields()[3], value);
       this.relatedids = value;
-      fieldSetFlags()[1] = true;
+      fieldSetFlags()[3] = true;
       return this; 
     }
     
     /** Checks whether the 'relatedids' field has been set */
     public boolean hasRelatedids() {
-      return fieldSetFlags()[1];
+      return fieldSetFlags()[3];
     }
     
     /** Clears the value of the 'relatedids' field */
     public org.apache.avro.FooBarSpecificRecord.Builder clearRelatedids() {
       relatedids = null;
-      fieldSetFlags()[1] = false;
+      fieldSetFlags()[3] = false;
       return this;
     }
 
@@ -199,21 +322,21 @@ public class FooBarSpecificRecord extend
     
     /** Sets the value of the 'typeEnum' field */
     public org.apache.avro.FooBarSpecificRecord.Builder setTypeEnum(org.apache.avro.TypeEnum value) {
-      validate(fields()[2], value);
+      validate(fields()[4], value);
       this.typeEnum = value;
-      fieldSetFlags()[2] = true;
+      fieldSetFlags()[4] = true;
       return this; 
     }
     
     /** Checks whether the 'typeEnum' field has been set */
     public boolean hasTypeEnum() {
-      return fieldSetFlags()[2];
+      return fieldSetFlags()[4];
     }
     
     /** Clears the value of the 'typeEnum' field */
     public org.apache.avro.FooBarSpecificRecord.Builder clearTypeEnum() {
       typeEnum = null;
-      fieldSetFlags()[2] = false;
+      fieldSetFlags()[4] = false;
       return this;
     }
 
@@ -222,12 +345,31 @@ public class FooBarSpecificRecord extend
       try {
         FooBarSpecificRecord record = new FooBarSpecificRecord();
         record.id = fieldSetFlags()[0] ? this.id : (java.lang.Integer) defaultValue(fields()[0]);
-        record.relatedids = fieldSetFlags()[1] ? this.relatedids : (java.util.List<java.lang.Integer>) defaultValue(fields()[1]);
-        record.typeEnum = fieldSetFlags()[2] ? this.typeEnum : (org.apache.avro.TypeEnum) defaultValue(fields()[2]);
+        record.name = fieldSetFlags()[1] ? this.name : (java.lang.String) defaultValue(fields()[1]);
+        record.nicknames = fieldSetFlags()[2] ? this.nicknames : (java.util.List<java.lang.String>) defaultValue(fields()[2]);
+        record.relatedids = fieldSetFlags()[3] ? this.relatedids : (java.util.List<java.lang.Integer>) defaultValue(fields()[3]);
+        record.typeEnum = fieldSetFlags()[4] ? this.typeEnum : (org.apache.avro.TypeEnum) defaultValue(fields()[4]);
         return record;
       } catch (Exception e) {
         throw new org.apache.avro.AvroRuntimeException(e);
       }
     }
   }
+
+  private static final org.apache.avro.io.DatumWriter
+    WRITER$ = new org.apache.avro.specific.SpecificDatumWriter(SCHEMA$);  
+
+  @Override public void writeExternal(java.io.ObjectOutput out)
+    throws java.io.IOException {
+    WRITER$.write(this, org.apache.avro.specific.SpecificData.getEncoder(out));
+  }
+
+  private static final org.apache.avro.io.DatumReader
+    READER$ = new org.apache.avro.specific.SpecificDatumReader(SCHEMA$);  
+
+  @Override public void readExternal(java.io.ObjectInput in)
+    throws java.io.IOException {
+    READER$.read(this, org.apache.avro.specific.SpecificData.getDecoder(in));
+  }
+
 }

Modified: avro/trunk/lang/java/avro/src/test/java/org/apache/avro/TypeEnum.java
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/avro/src/test/java/org/apache/avro/TypeEnum.java?rev=1629326&r1=1629325&r2=1629326&view=diff
==============================================================================
--- avro/trunk/lang/java/avro/src/test/java/org/apache/avro/TypeEnum.java (original)
+++ avro/trunk/lang/java/avro/src/test/java/org/apache/avro/TypeEnum.java Fri Oct  3 21:24:48 2014
@@ -5,7 +5,9 @@
  */
 package org.apache.avro;  
 @SuppressWarnings("all")
+@org.apache.avro.specific.AvroGenerated
 public enum TypeEnum { 
   a, b, c  ;
   public static final org.apache.avro.Schema SCHEMA$ = new org.apache.avro.Schema.Parser().parse("{\"type\":\"enum\",\"name\":\"TypeEnum\",\"namespace\":\"org.apache.avro\",\"symbols\":[\"a\",\"b\",\"c\"]}");
+  public static org.apache.avro.Schema getClassSchema() { return SCHEMA$; }
 }

Modified: avro/trunk/lang/java/avro/src/test/java/org/apache/avro/specific/TestSpecificData.java
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/avro/src/test/java/org/apache/avro/specific/TestSpecificData.java?rev=1629326&r1=1629325&r2=1629326&view=diff
==============================================================================
--- avro/trunk/lang/java/avro/src/test/java/org/apache/avro/specific/TestSpecificData.java (original)
+++ avro/trunk/lang/java/avro/src/test/java/org/apache/avro/specific/TestSpecificData.java Fri Oct  3 21:24:48 2014
@@ -120,6 +120,13 @@ public class TestSpecificData {
     public Schema getSchema() {
       return SCHEMA;
     }
+
+    @Override public void writeExternal(java.io.ObjectOutput out) {
+      throw new UnsupportedOperationException();
+    }
+    @Override public void readExternal(java.io.ObjectInput in) {
+      throw new UnsupportedOperationException();
+    }
   }
 
   @Test

Modified: avro/trunk/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java?rev=1629326&r1=1629325&r2=1629326&view=diff
==============================================================================
--- avro/trunk/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java (original)
+++ avro/trunk/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java Fri Oct  3 21:24:48 2014
@@ -41,6 +41,7 @@ import org.apache.avro.Protocol;
 import org.apache.avro.Protocol.Message;
 import org.apache.avro.Schema;
 import org.apache.avro.Schema.Field;
+import org.apache.avro.SchemaNormalization;
 import org.apache.avro.JsonProperties;
 import org.apache.avro.generic.GenericData;
 import org.apache.avro.generic.GenericData.StringType;
@@ -625,6 +626,11 @@ public class SpecificCompiler {
     return word;
   }
   
+  /** Utility for use by templates. Return schema fingerprint as a long. */
+  public static long fingerprint64(Schema schema) {
+    return SchemaNormalization.parsingFingerprint64(schema);
+  }
+
   /**
    * Generates the name of a field accessor method.
    * @param schema the schema in which the field is defined.

Modified: avro/trunk/lang/java/compiler/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/fixed.vm
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/compiler/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/fixed.vm?rev=1629326&r1=1629325&r2=1629326&view=diff
==============================================================================
--- avro/trunk/lang/java/compiler/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/fixed.vm (original)
+++ avro/trunk/lang/java/compiler/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/fixed.vm Fri Oct  3 21:24:48 2014
@@ -28,8 +28,10 @@ package $schema.getNamespace();  
 @org.apache.avro.specific.FixedSize($schema.getFixedSize())
 @org.apache.avro.specific.AvroGenerated
 public class ${this.mangle($schema.getName())} extends org.apache.avro.specific.SpecificFixed {
+  private static final long serialVersionUID = ${this.fingerprint64($schema)}L;
   public static final org.apache.avro.Schema SCHEMA$ = new org.apache.avro.Schema.Parser().parse("${this.javaEscape($schema.toString())}");
   public static org.apache.avro.Schema getClassSchema() { return SCHEMA$; }
+  public org.apache.avro.Schema getSchema() { return SCHEMA$; }
   
   /** Creates a new ${this.mangle($schema.getName())} */
   public ${this.mangle($schema.getName())}() {
@@ -40,4 +42,21 @@ public class ${this.mangle($schema.getNa
   public ${this.mangle($schema.getName())}(byte[] bytes) {
     super(bytes);
   }
+
+  private static final org.apache.avro.io.DatumWriter
+    WRITER$ = new org.apache.avro.specific.SpecificDatumWriter(SCHEMA$);  
+
+  @Override public void writeExternal(java.io.ObjectOutput out)
+    throws java.io.IOException {
+    WRITER$.write(this, org.apache.avro.specific.SpecificData.getEncoder(out));
+  }
+
+  private static final org.apache.avro.io.DatumReader
+    READER$ = new org.apache.avro.specific.SpecificDatumReader(SCHEMA$);  
+
+  @Override public void readExternal(java.io.ObjectInput in)
+    throws java.io.IOException {
+    READER$.read(this, org.apache.avro.specific.SpecificData.getDecoder(in));
+  }
+
 }

Modified: avro/trunk/lang/java/compiler/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/record.vm
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/compiler/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/record.vm?rev=1629326&r1=1629325&r2=1629326&view=diff
==============================================================================
--- avro/trunk/lang/java/compiler/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/record.vm (original)
+++ avro/trunk/lang/java/compiler/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/record.vm Fri Oct  3 21:24:48 2014
@@ -27,6 +27,7 @@ package $schema.getNamespace();  
 #end
 @org.apache.avro.specific.AvroGenerated
 public class ${this.mangle($schema.getName())}#if ($schema.isError()) extends org.apache.avro.specific.SpecificExceptionBase#else extends org.apache.avro.specific.SpecificRecordBase#end implements org.apache.avro.specific.SpecificRecord {
+  private static final long serialVersionUID = ${this.fingerprint64($schema)}L;
   public static final org.apache.avro.Schema SCHEMA$ = new org.apache.avro.Schema.Parser().parse(${this.javaSplit($schema.toString())});
   public static org.apache.avro.Schema getClassSchema() { return SCHEMA$; }
 #foreach ($field in $schema.getFields())
@@ -245,4 +246,21 @@ public class ${this.mangle($schema.getNa
       }
     }
   }
+
+  private static final org.apache.avro.io.DatumWriter
+    WRITER$ = new org.apache.avro.specific.SpecificDatumWriter(SCHEMA$);  
+
+  @Override public void writeExternal(java.io.ObjectOutput out)
+    throws java.io.IOException {
+    WRITER$.write(this, org.apache.avro.specific.SpecificData.getEncoder(out));
+  }
+
+  private static final org.apache.avro.io.DatumReader
+    READER$ = new org.apache.avro.specific.SpecificDatumReader(SCHEMA$);  
+
+  @Override public void readExternal(java.io.ObjectInput in)
+    throws java.io.IOException {
+    READER$.read(this, org.apache.avro.specific.SpecificData.getDecoder(in));
+  }
+
 }

Modified: avro/trunk/lang/java/ipc/src/test/java/org/apache/avro/specific/TestSpecificData.java
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/ipc/src/test/java/org/apache/avro/specific/TestSpecificData.java?rev=1629326&r1=1629325&r2=1629326&view=diff
==============================================================================
--- avro/trunk/lang/java/ipc/src/test/java/org/apache/avro/specific/TestSpecificData.java (original)
+++ avro/trunk/lang/java/ipc/src/test/java/org/apache/avro/specific/TestSpecificData.java Fri Oct  3 21:24:48 2014
@@ -23,6 +23,11 @@ import java.util.List;
 import java.util.Map;
 import java.util.ArrayList;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
 import org.apache.avro.FooBarSpecificRecord;
 import org.apache.avro.TypeEnum;
 import org.codehaus.jackson.JsonFactory;
@@ -120,4 +125,23 @@ public class TestSpecificData {
     mapper.readTree(parser);
   }
 
+  @Test public void testExternalizeable() throws Exception {
+    TestRecord before = new TestRecord();
+    before.setName("foo");
+    before.setKind(Kind.BAR);
+    before.setHash(new MD5(new byte[]{0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5}));
+    ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+    ObjectOutputStream out = new ObjectOutputStream(bytes);
+    out.writeObject(before);
+    out.close();
+
+    ObjectInputStream in =
+      new ObjectInputStream(new ByteArrayInputStream(bytes.toByteArray()));
+    TestRecord after = (TestRecord)in.readObject();
+
+    Assert.assertEquals(before, after);
+
+  }
+
 }
+

Modified: avro/trunk/lang/java/tools/src/test/compiler/output-string/avro/examples/baseball/Player.java
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/tools/src/test/compiler/output-string/avro/examples/baseball/Player.java?rev=1629326&r1=1629325&r2=1629326&view=diff
==============================================================================
--- avro/trunk/lang/java/tools/src/test/compiler/output-string/avro/examples/baseball/Player.java (original)
+++ avro/trunk/lang/java/tools/src/test/compiler/output-string/avro/examples/baseball/Player.java Fri Oct  3 21:24:48 2014
@@ -4,9 +4,11 @@
  * DO NOT EDIT DIRECTLY
  */
 package avro.examples.baseball;  
-@SuppressWarnings("all")/** 選手 is Japanese for player. */
+@SuppressWarnings("all")
+/** 選手 is Japanese for player. */
 @org.apache.avro.specific.AvroGenerated
 public class Player extends org.apache.avro.specific.SpecificRecordBase implements org.apache.avro.specific.SpecificRecord {
+  private static final long serialVersionUID = 3865593031278745715L;
   public static final org.apache.avro.Schema SCHEMA$ = new org.apache.avro.Schema.Parser().parse("{\"type\":\"record\",\"name\":\"Player\",\"namespace\":\"avro.examples.baseball\",\"doc\":\"選手 is Japanese for player.\",\"fields\":[{\"name\":\"number\",\"type\":\"int\"},{\"name\":\"first_name\",\"type\":{\"type\":\"string\",\"avro.java.string\":\"String\"}},{\"name\":\"last_name\",\"type\":{\"type\":\"string\",\"avro.java.string\":\"String\"}},{\"name\":\"position\",\"type\":{\"type\":\"array\",\"items\":{\"type\":\"enum\",\"name\":\"Position\",\"symbols\":[\"P\",\"C\",\"B1\",\"B2\",\"B3\",\"SS\",\"LF\",\"CF\",\"RF\",\"DH\"]}}}]}");
   public static org.apache.avro.Schema getClassSchema() { return SCHEMA$; }
   @Deprecated public int number;
@@ -300,4 +302,21 @@ public class Player extends org.apache.a
       }
     }
   }
+
+  private static final org.apache.avro.io.DatumWriter
+    WRITER$ = new org.apache.avro.specific.SpecificDatumWriter(SCHEMA$);  
+
+  @Override public void writeExternal(java.io.ObjectOutput out)
+    throws java.io.IOException {
+    WRITER$.write(this, org.apache.avro.specific.SpecificData.getEncoder(out));
+  }
+
+  private static final org.apache.avro.io.DatumReader
+    READER$ = new org.apache.avro.specific.SpecificDatumReader(SCHEMA$);  
+
+  @Override public void readExternal(java.io.ObjectInput in)
+    throws java.io.IOException {
+    READER$.read(this, org.apache.avro.specific.SpecificData.getDecoder(in));
+  }
+
 }

Modified: avro/trunk/lang/java/tools/src/test/compiler/output/Player.java
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/tools/src/test/compiler/output/Player.java?rev=1629326&r1=1629325&r2=1629326&view=diff
==============================================================================
--- avro/trunk/lang/java/tools/src/test/compiler/output/Player.java (original)
+++ avro/trunk/lang/java/tools/src/test/compiler/output/Player.java Fri Oct  3 21:24:48 2014
@@ -4,9 +4,11 @@
  * DO NOT EDIT DIRECTLY
  */
 package avro.examples.baseball;  
-@SuppressWarnings("all")/** 選手 is Japanese for player. */
+@SuppressWarnings("all")
+/** 選手 is Japanese for player. */
 @org.apache.avro.specific.AvroGenerated
 public class Player extends org.apache.avro.specific.SpecificRecordBase implements org.apache.avro.specific.SpecificRecord {
+  private static final long serialVersionUID = 3865593031278745715L;
   public static final org.apache.avro.Schema SCHEMA$ = new org.apache.avro.Schema.Parser().parse("{\"type\":\"record\",\"name\":\"Player\",\"namespace\":\"avro.examples.baseball\",\"doc\":\"選手 is Japanese for player.\",\"fields\":[{\"name\":\"number\",\"type\":\"int\"},{\"name\":\"first_name\",\"type\":\"string\"},{\"name\":\"last_name\",\"type\":\"string\"},{\"name\":\"position\",\"type\":{\"type\":\"array\",\"items\":{\"type\":\"enum\",\"name\":\"Position\",\"symbols\":[\"P\",\"C\",\"B1\",\"B2\",\"B3\",\"SS\",\"LF\",\"CF\",\"RF\",\"DH\"]}}}]}");
   public static org.apache.avro.Schema getClassSchema() { return SCHEMA$; }
   @Deprecated public int number;
@@ -300,4 +302,21 @@ public class Player extends org.apache.a
       }
     }
   }
+
+  private static final org.apache.avro.io.DatumWriter
+    WRITER$ = new org.apache.avro.specific.SpecificDatumWriter(SCHEMA$);  
+
+  @Override public void writeExternal(java.io.ObjectOutput out)
+    throws java.io.IOException {
+    WRITER$.write(this, org.apache.avro.specific.SpecificData.getEncoder(out));
+  }
+
+  private static final org.apache.avro.io.DatumReader
+    READER$ = new org.apache.avro.specific.SpecificDatumReader(SCHEMA$);  
+
+  @Override public void readExternal(java.io.ObjectInput in)
+    throws java.io.IOException {
+    READER$.read(this, org.apache.avro.specific.SpecificData.getDecoder(in));
+  }
+
 }