You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@avro.apache.org by ni...@apache.org on 2017/12/18 10:48:27 UTC

avro git commit: AVRO-2114: Make missing value exceptions in nested structures easier to read. This closes #269

Repository: avro
Updated Branches:
  refs/heads/branch-1.8 1511b67da -> bb2c80407


AVRO-2114: Make missing value exceptions in nested structures easier to read.
This closes #269


Project: http://git-wip-us.apache.org/repos/asf/avro/repo
Commit: http://git-wip-us.apache.org/repos/asf/avro/commit/bb2c8040
Tree: http://git-wip-us.apache.org/repos/asf/avro/tree/bb2c8040
Diff: http://git-wip-us.apache.org/repos/asf/avro/diff/bb2c8040

Branch: refs/heads/branch-1.8
Commit: bb2c804079b2377c47692baa09f2b63ba6fa05fe
Parents: 1511b67
Author: Niels Basjes <nb...@bol.com>
Authored: Tue Dec 12 13:09:40 2017 +0100
Committer: Niels Basjes <nb...@bol.com>
Committed: Mon Dec 18 11:43:16 2017 +0100

----------------------------------------------------------------------
 CHANGES.txt                                     |   3 +
 .../apache/avro/AvroMissingFieldException.java  |  46 ++++
 .../org/apache/avro/generic/GenericData.java    |   5 +-
 .../org/apache/avro/FooBarSpecificRecord.java   | 248 +++++++++++++++----
 .../specific/templates/java/classic/record.vm   |   9 +-
 .../avro/specific/TestSpecificBuilderTree.java  |  12 +-
 .../avro/examples/baseball/Player.java          |   2 +
 .../tools/src/test/compiler/output/Player.java  |   2 +
 8 files changed, 278 insertions(+), 49 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/avro/blob/bb2c8040/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index f8eefc4..27721b6 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -16,6 +16,9 @@ Trunk (not yet released)
     AVRO-2080: Fix Javadoc Warnings in Generated Records
     (Bridger Howell via Niels Basjes)
 
+    AVRO-2114: Make missing value exceptions in nested structures easier to read.
+    (Niels Basjes)
+
   BUG FIXES
 
     AVRO-1401: @Nullable does not work with byte[] (Nandor Kollar via gabor)

http://git-wip-us.apache.org/repos/asf/avro/blob/bb2c8040/lang/java/avro/src/main/java/org/apache/avro/AvroMissingFieldException.java
----------------------------------------------------------------------
diff --git a/lang/java/avro/src/main/java/org/apache/avro/AvroMissingFieldException.java b/lang/java/avro/src/main/java/org/apache/avro/AvroMissingFieldException.java
new file mode 100644
index 0000000..f036b3a
--- /dev/null
+++ b/lang/java/avro/src/main/java/org/apache/avro/AvroMissingFieldException.java
@@ -0,0 +1,46 @@
+/*
+ * 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;
+
+import org.apache.avro.Schema.Field;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Avro exception in case of missing fields. */
+public class AvroMissingFieldException extends AvroRuntimeException {
+  private List<Field> chainOfFields = new ArrayList<Field>(8);
+  public AvroMissingFieldException(String message, Field field) {
+    super(message);
+    chainOfFields.add(field);
+  }
+
+  public void addParentField(Field field) {
+    chainOfFields.add(field);
+  }
+
+  @Override
+  public String toString() {
+    String result = "";
+    for (Field field: chainOfFields) {
+      result = " --> " + field.name() + result;
+    }
+    return "Path in schema:" + result;
+  }
+}

http://git-wip-us.apache.org/repos/asf/avro/blob/bb2c8040/lang/java/avro/src/main/java/org/apache/avro/generic/GenericData.java
----------------------------------------------------------------------
diff --git a/lang/java/avro/src/main/java/org/apache/avro/generic/GenericData.java b/lang/java/avro/src/main/java/org/apache/avro/generic/GenericData.java
index ff0893c..67d47d9 100644
--- a/lang/java/avro/src/main/java/org/apache/avro/generic/GenericData.java
+++ b/lang/java/avro/src/main/java/org/apache/avro/generic/GenericData.java
@@ -31,6 +31,7 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.avro.AvroMissingFieldException;
 import org.apache.avro.AvroRuntimeException;
 import org.apache.avro.AvroTypeException;
 import org.apache.avro.Conversion;
@@ -1012,8 +1013,8 @@ public class GenericData {
   public Object getDefaultValue(Field field) {
     JsonNode json = field.defaultValue();
     if (json == null)
-      throw new AvroRuntimeException("Field " + field
-                                     + " not set and has no default value");
+      throw new AvroMissingFieldException("Field " + field
+                                          + " not set and has no default value", field);
     if (json.isNull()
         && (field.schema().getType() == Type.NULL
             || (field.schema().getType() == Type.UNION

http://git-wip-us.apache.org/repos/asf/avro/blob/bb2c8040/lang/java/avro/src/test/java/org/apache/avro/FooBarSpecificRecord.java
----------------------------------------------------------------------
diff --git a/lang/java/avro/src/test/java/org/apache/avro/FooBarSpecificRecord.java b/lang/java/avro/src/test/java/org/apache/avro/FooBarSpecificRecord.java
index bab3620..e273786 100644
--- a/lang/java/avro/src/test/java/org/apache/avro/FooBarSpecificRecord.java
+++ b/lang/java/avro/src/test/java/org/apache/avro/FooBarSpecificRecord.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Autogenerated by Avro
  *
  * DO NOT EDIT DIRECTLY
@@ -20,12 +20,63 @@
  * limitations under the License.
  */
 package org.apache.avro;
-@SuppressWarnings("all")
+
+import org.apache.avro.specific.SpecificData;
+import org.apache.avro.message.BinaryMessageEncoder;
+import org.apache.avro.message.BinaryMessageDecoder;
+import org.apache.avro.message.SchemaStore;
+
 @org.apache.avro.specific.AvroGenerated
 public class FooBarSpecificRecord extends org.apache.avro.specific.SpecificRecordBase implements org.apache.avro.specific.SpecificRecord {
   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$; }
+
+  private static SpecificData MODEL$ = new SpecificData();
+
+  private static final BinaryMessageEncoder<FooBarSpecificRecord> ENCODER =
+      new BinaryMessageEncoder<FooBarSpecificRecord>(MODEL$, SCHEMA$);
+
+  private static final BinaryMessageDecoder<FooBarSpecificRecord> DECODER =
+      new BinaryMessageDecoder<FooBarSpecificRecord>(MODEL$, SCHEMA$);
+
+  /**
+   * Return the BinaryMessageDecoder instance used by this class.
+   * @return the message decoder used by this class
+   */
+  public static BinaryMessageDecoder<FooBarSpecificRecord> getDecoder() {
+    return DECODER;
+  }
+
+  /**
+   * Create a new BinaryMessageDecoder instance for this class that uses the specified {@link SchemaStore}.
+   * @param resolver a {@link SchemaStore} used to find schemas by fingerprint
+   * @return a BinaryMessageDecoder instance for this class backed by the given SchemaStore
+   */
+  public static BinaryMessageDecoder<FooBarSpecificRecord> createDecoder(SchemaStore resolver) {
+    return new BinaryMessageDecoder<FooBarSpecificRecord>(MODEL$, SCHEMA$, resolver);
+  }
+
+  /**
+   * Serializes this FooBarSpecificRecord to a ByteBuffer.
+   * @return a buffer holding the serialized data for this instance
+   * @throws java.io.IOException if this instance could not be serialized
+   */
+  public java.nio.ByteBuffer toByteBuffer() throws java.io.IOException {
+    return ENCODER.encode(this);
+  }
+
+  /**
+   * Deserializes a FooBarSpecificRecord from a ByteBuffer.
+   * @param b a byte buffer holding serialized data for an instance of this class
+   * @return a FooBarSpecificRecord instance decoded from the given buffer
+   * @throws java.io.IOException if the given bytes could not be deserialized into an instance of this class
+   */
+  public static FooBarSpecificRecord fromByteBuffer(
+      java.nio.ByteBuffer b) throws java.io.IOException {
+    return DECODER.decode(b);
+  }
+
   @Deprecated public int id;
   @Deprecated public java.lang.String name;
   @Deprecated public java.util.List<java.lang.String> nicknames;
@@ -41,6 +92,11 @@ public class FooBarSpecificRecord extends org.apache.avro.specific.SpecificRecor
 
   /**
    * All-args constructor.
+   * @param id The new value for id
+   * @param name The new value for name
+   * @param nicknames The new value for nicknames
+   * @param relatedids The new value for relatedids
+   * @param typeEnum The new value for 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;
@@ -62,6 +118,7 @@ public class FooBarSpecificRecord extends org.apache.avro.specific.SpecificRecor
     default: throw new org.apache.avro.AvroRuntimeException("Bad index");
     }
   }
+
   // Used by DatumReader.  Applications should not call.
   @SuppressWarnings(value="unchecked")
   public void put(int field$, java.lang.Object value$) {
@@ -77,6 +134,7 @@ public class FooBarSpecificRecord extends org.apache.avro.specific.SpecificRecor
 
   /**
    * Gets the value of the 'id' field.
+   * @return The value of the 'id' field.
    */
   public java.lang.Integer getId() {
     return id;
@@ -92,6 +150,7 @@ public class FooBarSpecificRecord extends org.apache.avro.specific.SpecificRecor
 
   /**
    * Gets the value of the 'name' field.
+   * @return The value of the 'name' field.
    */
   public java.lang.String getName() {
     return name;
@@ -107,6 +166,7 @@ public class FooBarSpecificRecord extends org.apache.avro.specific.SpecificRecor
 
   /**
    * Gets the value of the 'nicknames' field.
+   * @return The value of the 'nicknames' field.
    */
   public java.util.List<java.lang.String> getNicknames() {
     return nicknames;
@@ -122,6 +182,7 @@ public class FooBarSpecificRecord extends org.apache.avro.specific.SpecificRecor
 
   /**
    * Gets the value of the 'relatedids' field.
+   * @return The value of the 'relatedids' field.
    */
   public java.util.List<java.lang.Integer> getRelatedids() {
     return relatedids;
@@ -137,6 +198,7 @@ public class FooBarSpecificRecord extends org.apache.avro.specific.SpecificRecor
 
   /**
    * Gets the value of the 'typeEnum' field.
+   * @return The value of the 'typeEnum' field.
    */
   public org.apache.avro.TypeEnum getTypeEnum() {
     return typeEnum;
@@ -150,19 +212,38 @@ public class FooBarSpecificRecord extends org.apache.avro.specific.SpecificRecor
     this.typeEnum = value;
   }
 
-  /** Creates a new FooBarSpecificRecord RecordBuilder */
+  /**
+   * Creates a new FooBarSpecificRecord RecordBuilder.
+   * @return A new FooBarSpecificRecord RecordBuilder
+   */
   public static org.apache.avro.FooBarSpecificRecord.Builder newBuilder() {
     return new org.apache.avro.FooBarSpecificRecord.Builder();
   }
 
-  /** Creates a new FooBarSpecificRecord RecordBuilder by copying an existing Builder */
+  /**
+   * Creates a new FooBarSpecificRecord RecordBuilder by copying an existing Builder.
+   * @param other The existing builder to copy.
+   * @return A new FooBarSpecificRecord RecordBuilder
+   */
   public static org.apache.avro.FooBarSpecificRecord.Builder newBuilder(org.apache.avro.FooBarSpecificRecord.Builder other) {
-    return new org.apache.avro.FooBarSpecificRecord.Builder(other);
+    if (other == null) {
+      return new org.apache.avro.FooBarSpecificRecord.Builder();
+    } else {
+      return new org.apache.avro.FooBarSpecificRecord.Builder(other);
+    }
   }
 
-  /** Creates a new FooBarSpecificRecord RecordBuilder by copying an existing FooBarSpecificRecord instance */
+  /**
+   * Creates a new FooBarSpecificRecord RecordBuilder by copying an existing FooBarSpecificRecord instance.
+   * @param other The existing instance to copy.
+   * @return A new FooBarSpecificRecord RecordBuilder
+   */
   public static org.apache.avro.FooBarSpecificRecord.Builder newBuilder(org.apache.avro.FooBarSpecificRecord other) {
-    return new org.apache.avro.FooBarSpecificRecord.Builder(other);
+    if (other == null) {
+      return new org.apache.avro.FooBarSpecificRecord.Builder();
+    } else {
+      return new org.apache.avro.FooBarSpecificRecord.Builder(other);
+    }
   }
 
   /**
@@ -179,37 +260,43 @@ public class FooBarSpecificRecord extends org.apache.avro.specific.SpecificRecor
 
     /** Creates a new Builder */
     private Builder() {
-      super(org.apache.avro.FooBarSpecificRecord.SCHEMA$);
+      super(SCHEMA$);
     }
 
-    /** Creates a Builder by copying an existing Builder */
+    /**
+     * Creates a Builder by copying an existing Builder.
+     * @param other The existing Builder to copy.
+     */
     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;
+        fieldSetFlags()[0] = other.fieldSetFlags()[0];
       }
       if (isValidValue(fields()[1], other.name)) {
         this.name = data().deepCopy(fields()[1].schema(), other.name);
-        fieldSetFlags()[1] = true;
+        fieldSetFlags()[1] = other.fieldSetFlags()[1];
       }
       if (isValidValue(fields()[2], other.nicknames)) {
         this.nicknames = data().deepCopy(fields()[2].schema(), other.nicknames);
-        fieldSetFlags()[2] = true;
+        fieldSetFlags()[2] = other.fieldSetFlags()[2];
       }
       if (isValidValue(fields()[3], other.relatedids)) {
         this.relatedids = data().deepCopy(fields()[3].schema(), other.relatedids);
-        fieldSetFlags()[3] = true;
+        fieldSetFlags()[3] = other.fieldSetFlags()[3];
       }
       if (isValidValue(fields()[4], other.typeEnum)) {
         this.typeEnum = data().deepCopy(fields()[4].schema(), other.typeEnum);
-        fieldSetFlags()[4] = true;
+        fieldSetFlags()[4] = other.fieldSetFlags()[4];
       }
     }
 
-    /** Creates a Builder by copying an existing FooBarSpecificRecord instance */
+    /**
+     * Creates a Builder by copying an existing FooBarSpecificRecord instance
+     * @param other The existing instance to copy.
+     */
     private Builder(org.apache.avro.FooBarSpecificRecord other) {
-            super(org.apache.avro.FooBarSpecificRecord.SCHEMA$);
+      super(SCHEMA$);
       if (isValidValue(fields()[0], other.id)) {
         this.id = data().deepCopy(fields()[0].schema(), other.id);
         fieldSetFlags()[0] = true;
@@ -232,12 +319,19 @@ public class FooBarSpecificRecord extends org.apache.avro.specific.SpecificRecor
       }
     }
 
-    /** Gets the value of the 'id' field */
+    /**
+      * Gets the value of the 'id' field.
+      * @return The value.
+      */
     public java.lang.Integer getId() {
       return id;
     }
 
-    /** Sets the value of the 'id' field */
+    /**
+      * Sets the value of the 'id' field.
+      * @param value The value of 'id'.
+      * @return This builder.
+      */
     public org.apache.avro.FooBarSpecificRecord.Builder setId(int value) {
       validate(fields()[0], value);
       this.id = value;
@@ -245,23 +339,37 @@ public class FooBarSpecificRecord extends org.apache.avro.specific.SpecificRecor
       return this;
     }
 
-    /** Checks whether the 'id' field has been set */
+    /**
+      * Checks whether the 'id' field has been set.
+      * @return True if the 'id' field has been set, false otherwise.
+      */
     public boolean hasId() {
       return fieldSetFlags()[0];
     }
 
-    /** Clears the value of the 'id' field */
+
+    /**
+      * Clears the value of the 'id' field.
+      * @return This builder.
+      */
     public org.apache.avro.FooBarSpecificRecord.Builder clearId() {
       fieldSetFlags()[0] = false;
       return this;
     }
 
-    /** Gets the value of the 'name' field */
+    /**
+      * Gets the value of the 'name' field.
+      * @return The value.
+      */
     public java.lang.String getName() {
       return name;
     }
 
-    /** Sets the value of the 'name' field */
+    /**
+      * Sets the value of the 'name' field.
+      * @param value The value of 'name'.
+      * @return This builder.
+      */
     public org.apache.avro.FooBarSpecificRecord.Builder setName(java.lang.String value) {
       validate(fields()[1], value);
       this.name = value;
@@ -269,24 +377,38 @@ public class FooBarSpecificRecord extends org.apache.avro.specific.SpecificRecor
       return this;
     }
 
-    /** Checks whether the 'name' field has been set */
+    /**
+      * Checks whether the 'name' field has been set.
+      * @return True if the 'name' field has been set, false otherwise.
+      */
     public boolean hasName() {
       return fieldSetFlags()[1];
     }
 
-    /** Clears the value of the 'name' field */
+
+    /**
+      * Clears the value of the 'name' field.
+      * @return This builder.
+      */
     public org.apache.avro.FooBarSpecificRecord.Builder clearName() {
       name = null;
       fieldSetFlags()[1] = false;
       return this;
     }
 
-    /** Gets the value of the 'nicknames' field */
+    /**
+      * Gets the value of the 'nicknames' field.
+      * @return The value.
+      */
     public java.util.List<java.lang.String> getNicknames() {
       return nicknames;
     }
 
-    /** Sets the value of the 'nicknames' field */
+    /**
+      * Sets the value of the 'nicknames' field.
+      * @param value The value of 'nicknames'.
+      * @return This builder.
+      */
     public org.apache.avro.FooBarSpecificRecord.Builder setNicknames(java.util.List<java.lang.String> value) {
       validate(fields()[2], value);
       this.nicknames = value;
@@ -294,24 +416,38 @@ public class FooBarSpecificRecord extends org.apache.avro.specific.SpecificRecor
       return this;
     }
 
-    /** Checks whether the 'nicknames' field has been set */
+    /**
+      * Checks whether the 'nicknames' field has been set.
+      * @return True if the 'nicknames' field has been set, false otherwise.
+      */
     public boolean hasNicknames() {
       return fieldSetFlags()[2];
     }
 
-    /** Clears the value of the 'nicknames' field */
+
+    /**
+      * Clears the value of the 'nicknames' field.
+      * @return This builder.
+      */
     public org.apache.avro.FooBarSpecificRecord.Builder clearNicknames() {
       nicknames = null;
       fieldSetFlags()[2] = false;
       return this;
     }
 
-    /** Gets the value of the 'relatedids' field */
+    /**
+      * Gets the value of the 'relatedids' field.
+      * @return The value.
+      */
     public java.util.List<java.lang.Integer> getRelatedids() {
       return relatedids;
     }
 
-    /** Sets the value of the 'relatedids' field */
+    /**
+      * Sets the value of the 'relatedids' field.
+      * @param value The value of 'relatedids'.
+      * @return This builder.
+      */
     public org.apache.avro.FooBarSpecificRecord.Builder setRelatedids(java.util.List<java.lang.Integer> value) {
       validate(fields()[3], value);
       this.relatedids = value;
@@ -319,24 +455,38 @@ public class FooBarSpecificRecord extends org.apache.avro.specific.SpecificRecor
       return this;
     }
 
-    /** Checks whether the 'relatedids' field has been set */
+    /**
+      * Checks whether the 'relatedids' field has been set.
+      * @return True if the 'relatedids' field has been set, false otherwise.
+      */
     public boolean hasRelatedids() {
       return fieldSetFlags()[3];
     }
 
-    /** Clears the value of the 'relatedids' field */
+
+    /**
+      * Clears the value of the 'relatedids' field.
+      * @return This builder.
+      */
     public org.apache.avro.FooBarSpecificRecord.Builder clearRelatedids() {
       relatedids = null;
       fieldSetFlags()[3] = false;
       return this;
     }
 
-    /** Gets the value of the 'typeEnum' field */
+    /**
+      * Gets the value of the 'typeEnum' field.
+      * @return The value.
+      */
     public org.apache.avro.TypeEnum getTypeEnum() {
       return typeEnum;
     }
 
-    /** Sets the value of the 'typeEnum' field */
+    /**
+      * Sets the value of the 'typeEnum' field.
+      * @param value The value of 'typeEnum'.
+      * @return This builder.
+      */
     public org.apache.avro.FooBarSpecificRecord.Builder setTypeEnum(org.apache.avro.TypeEnum value) {
       validate(fields()[4], value);
       this.typeEnum = value;
@@ -344,12 +494,19 @@ public class FooBarSpecificRecord extends org.apache.avro.specific.SpecificRecor
       return this;
     }
 
-    /** Checks whether the 'typeEnum' field has been set */
+    /**
+      * Checks whether the 'typeEnum' field has been set.
+      * @return True if the 'typeEnum' field has been set, false otherwise.
+      */
     public boolean hasTypeEnum() {
       return fieldSetFlags()[4];
     }
 
-    /** Clears the value of the 'typeEnum' field */
+
+    /**
+      * Clears the value of the 'typeEnum' field.
+      * @return This builder.
+      */
     public org.apache.avro.FooBarSpecificRecord.Builder clearTypeEnum() {
       typeEnum = null;
       fieldSetFlags()[4] = false;
@@ -357,6 +514,7 @@ public class FooBarSpecificRecord extends org.apache.avro.specific.SpecificRecor
     }
 
     @Override
+    @SuppressWarnings("unchecked")
     public FooBarSpecificRecord build() {
       try {
         FooBarSpecificRecord record = new FooBarSpecificRecord();
@@ -366,26 +524,30 @@ public class FooBarSpecificRecord extends org.apache.avro.specific.SpecificRecor
         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) {
+      } catch (org.apache.avro.AvroMissingFieldException e) {
+        throw e;
+      } catch (java.lang.Exception e) {
         throw new org.apache.avro.AvroRuntimeException(e);
       }
     }
   }
 
-  private static final org.apache.avro.io.DatumWriter
-    WRITER$ = new org.apache.avro.specific.SpecificDatumWriter<FooBarSpecificRecord>(SCHEMA$);
+  @SuppressWarnings("unchecked")
+  private static final org.apache.avro.io.DatumWriter<FooBarSpecificRecord>
+    WRITER$ = (org.apache.avro.io.DatumWriter<FooBarSpecificRecord>)MODEL$.createDatumWriter(SCHEMA$);
 
   @Override public void writeExternal(java.io.ObjectOutput out)
     throws java.io.IOException {
-    WRITER$.write(this, org.apache.avro.specific.SpecificData.getEncoder(out));
+    WRITER$.write(this, SpecificData.getEncoder(out));
   }
 
-  private static final org.apache.avro.io.DatumReader
-    READER$ = new org.apache.avro.specific.SpecificDatumReader<FooBarSpecificRecord>(SCHEMA$);
+  @SuppressWarnings("unchecked")
+  private static final org.apache.avro.io.DatumReader<FooBarSpecificRecord>
+    READER$ = (org.apache.avro.io.DatumReader<FooBarSpecificRecord>)MODEL$.createDatumReader(SCHEMA$);
 
   @Override public void readExternal(java.io.ObjectInput in)
     throws java.io.IOException {
-    READER$.read(this, org.apache.avro.specific.SpecificData.getDecoder(in));
+    READER$.read(this, SpecificData.getDecoder(in));
   }
 
 }

http://git-wip-us.apache.org/repos/asf/avro/blob/bb2c8040/lang/java/compiler/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/record.vm
----------------------------------------------------------------------
diff --git a/lang/java/compiler/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/record.vm b/lang/java/compiler/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/record.vm
index f55c1ff..94090d8 100644
--- a/lang/java/compiler/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/record.vm
+++ b/lang/java/compiler/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/record.vm
@@ -434,7 +434,12 @@ public class ${this.mangle($schema.getName())}#if ($schema.isError()) extends or
 #foreach ($field in $schema.getFields())
 #if (${this.hasBuilder($field.schema())})
         if (${this.mangle($field.name(), $schema.isError())}Builder != null) {
-          record.${this.mangle($field.name(), $schema.isError())} = this.${this.mangle($field.name(), $schema.isError())}Builder.build();
+          try {
+            record.${this.mangle($field.name(), $schema.isError())} = this.${this.mangle($field.name(), $schema.isError())}Builder.build();
+          } catch (org.apache.avro.AvroMissingFieldException e) {
+            e.addParentField(record.getSchema().getField("${this.mangle($field.name(), $schema.isError())}"));
+            throw e;
+          }
         } else {
 #if ($this.hasLogicalTypeField($schema))
           record.${this.mangle($field.name(), $schema.isError())} = fieldSetFlags()[$field.pos()] ? this.${this.mangle($field.name(), $schema.isError())} : #if(${this.javaType($field.schema())} != "java.lang.Object")(${this.javaType($field.schema())})#{end} defaultValue(fields()[$field.pos()], record.getConversion($field.pos()));
@@ -451,6 +456,8 @@ public class ${this.mangle($schema.getName())}#if ($schema.isError()) extends or
 #end
 #end
         return record;
+      } catch (org.apache.avro.AvroMissingFieldException e) {
+        throw e;
       } catch (java.lang.Exception e) {
         throw new org.apache.avro.AvroRuntimeException(e);
       }

http://git-wip-us.apache.org/repos/asf/avro/blob/bb2c8040/lang/java/ipc/src/test/java/org/apache/avro/specific/TestSpecificBuilderTree.java
----------------------------------------------------------------------
diff --git a/lang/java/ipc/src/test/java/org/apache/avro/specific/TestSpecificBuilderTree.java b/lang/java/ipc/src/test/java/org/apache/avro/specific/TestSpecificBuilderTree.java
index a0ad619..24afd52 100644
--- a/lang/java/ipc/src/test/java/org/apache/avro/specific/TestSpecificBuilderTree.java
+++ b/lang/java/ipc/src/test/java/org/apache/avro/specific/TestSpecificBuilderTree.java
@@ -17,6 +17,7 @@
  */
 package org.apache.avro.specific;
 
+import org.apache.avro.AvroMissingFieldException;
 import org.apache.avro.test.http.*;
 import org.junit.Test;
 
@@ -66,10 +67,15 @@ public class TestSpecificBuilderTree {
     return requestBuilder;
   }
 
-  @Test(expected = org.apache.avro.AvroRuntimeException.class)
+  @Test(expected = AvroMissingFieldException.class)
   public void failOnIncompleteTree() {
-    Request.Builder requestBuilder = createPartialBuilder();
-    Request request = requestBuilder.build();
+    try {
+      createPartialBuilder().build();
+    } catch (AvroMissingFieldException amfe) {
+      assertEquals("Field networkAddress type:STRING pos:1 not set and has no default value", amfe.getMessage());
+      assertEquals("Path in schema: --> connection --> networkAddress", amfe.toString());
+      throw amfe;
+    }
     fail("Should NEVER get here");
   }
 

http://git-wip-us.apache.org/repos/asf/avro/blob/bb2c8040/lang/java/tools/src/test/compiler/output-string/avro/examples/baseball/Player.java
----------------------------------------------------------------------
diff --git a/lang/java/tools/src/test/compiler/output-string/avro/examples/baseball/Player.java b/lang/java/tools/src/test/compiler/output-string/avro/examples/baseball/Player.java
index e534c2f..e8abfc7 100644
--- a/lang/java/tools/src/test/compiler/output-string/avro/examples/baseball/Player.java
+++ b/lang/java/tools/src/test/compiler/output-string/avro/examples/baseball/Player.java
@@ -438,6 +438,8 @@ public class Player extends org.apache.avro.specific.SpecificRecordBase implemen
         record.last_name = fieldSetFlags()[2] ? this.last_name : (java.lang.String) defaultValue(fields()[2]);
         record.position = fieldSetFlags()[3] ? this.position : (java.util.List<avro.examples.baseball.Position>) defaultValue(fields()[3]);
         return record;
+      } catch (org.apache.avro.AvroMissingFieldException e) {
+        throw e;
       } catch (java.lang.Exception e) {
         throw new org.apache.avro.AvroRuntimeException(e);
       }

http://git-wip-us.apache.org/repos/asf/avro/blob/bb2c8040/lang/java/tools/src/test/compiler/output/Player.java
----------------------------------------------------------------------
diff --git a/lang/java/tools/src/test/compiler/output/Player.java b/lang/java/tools/src/test/compiler/output/Player.java
index 382c067..eb0e2f2 100644
--- a/lang/java/tools/src/test/compiler/output/Player.java
+++ b/lang/java/tools/src/test/compiler/output/Player.java
@@ -438,6 +438,8 @@ public class Player extends org.apache.avro.specific.SpecificRecordBase implemen
         record.last_name = fieldSetFlags()[2] ? this.last_name : (java.lang.CharSequence) defaultValue(fields()[2]);
         record.position = fieldSetFlags()[3] ? this.position : (java.util.List<avro.examples.baseball.Position>) defaultValue(fields()[3]);
         return record;
+      } catch (org.apache.avro.AvroMissingFieldException e) {
+        throw e;
       } catch (java.lang.Exception e) {
         throw new org.apache.avro.AvroRuntimeException(e);
       }