You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@avro.apache.org by dk...@apache.org on 2018/11/02 20:54:26 UTC

[avro] branch master updated: Squashed commit of the following:

This is an automated email from the ASF dual-hosted git repository.

dkulp pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/avro.git


The following commit(s) were added to refs/heads/master by this push:
     new d799e18  Squashed commit of the following:
d799e18 is described below

commit d799e1829a39ca0379f3e12d2e8cfdf5fcd26151
Author: Daniel Kulp <dk...@apache.org>
AuthorDate: Fri Nov 2 16:40:09 2018 -0400

    Squashed commit of the following:
    
    commit 6d4d6d6a963fd2363d9f5549f76140bdddfceb7d
    Author: Gabor Szadovszky <ga...@cloudera.com>
    Date:   Sun Oct 16 17:22:53 2016 +0200
    
        AVRO-1605 - Removed some unnecessary Accessor methods and callers
    
    commit adcefac6cc1c7021b2a27da16b40c1253eff64cc
    Author: Gabor Szadovszky <ga...@cloudera.com>
    Date:   Thu Sep 29 18:35:26 2016 +0200
    
        AVRO-1605 - Remove Jackson classes from public API (Removed jackson references from javadoc)
    
    commit dc2ca7ee9f881901aaf23d9221cc2d6413b43dc4
    Author: Gabor Szadovszky <ga...@cloudera.com>
    Date:   Thu Sep 29 14:31:40 2016 +0200
    
        AVRO-1605 - Remove Jackson classes from public API
    
    commit 4e4c5ec63b3b0cf203e3af21c1cbc7a51d63c9f4
    Author: Gabor Szadovszky <ga...@cloudera.com>
    Date:   Wed Sep 28 17:08:15 2016 +0200
    
        AVRO-1605 - Remove Jackson classes from public API (INCOMPLETE#4)
    
    commit 5fb5a5c14fadc03f44879f029114c4705749dfad
    Author: Gabor Szadovszky <ga...@cloudera.com>
    Date:   Wed Sep 28 16:54:44 2016 +0200
    
        AVRO-1605 - Remove Jackson classes from public API (INCOMPLETE#3)
    
    commit 378fcc5aa6be560c301e23b73f919bc0eb98dd05
    Author: Gabor Szadovszky <ga...@cloudera.com>
    Date:   Wed Sep 28 11:11:40 2016 +0200
    
        AVRO-1605 - Remove Jackson classes from public API (INCOMPLETE#2)
    
    commit 12533657f9bc73c73b1009ed2d9dd39ca2401a20
    Author: Gabor Szadovszky <ga...@cloudera.com>
    Date:   Mon Sep 26 16:25:19 2016 +0200
    
        AVRO-1605 - Remove Jackson classes from public API (INCOMPLETE)
---
 .../main/java/org/apache/avro/JsonProperties.java  |  45 ++++----
 .../src/main/java/org/apache/avro/Protocol.java    |  21 ++++
 .../avro/src/main/java/org/apache/avro/Schema.java |  63 ++++++++---
 .../src/main/java/org/apache/avro/data/Json.java   |  54 +---------
 .../org/apache/avro/data/RecordBuilderBase.java    |   2 +-
 .../java/org/apache/avro/generic/GenericData.java  |   7 +-
 .../java/org/apache/avro/io/EncoderFactory.java    |   4 +-
 .../main/java/org/apache/avro/io/JsonEncoder.java  |   4 +-
 .../avro/io/parsing/ResolvingGrammarGenerator.java |  22 ++--
 .../java/org/apache/avro/reflect/ReflectData.java  |   9 +-
 .../org/apache/avro/util/internal/Accessor.java    | 119 +++++++++++++++++++++
 .../java/org/apache/avro/reflect/TestReflect.java  |   3 +-
 .../avro/compiler/specific/SpecificCompiler.java   |  53 +++++----
 .../javacc/org/apache/avro/compiler/idl/idl.jj     |  32 +++---
 .../org/apache/avro/protobuf/ProtobufData.java     |   3 +-
 .../java/org/apache/avro/tool/RpcSendTool.java     |  13 +--
 .../java/org/apache/trevni/avro/RandomData.java    |   2 +-
 17 files changed, 294 insertions(+), 162 deletions(-)

diff --git a/lang/java/avro/src/main/java/org/apache/avro/JsonProperties.java b/lang/java/avro/src/main/java/org/apache/avro/JsonProperties.java
index 97493fc..3844073 100644
--- a/lang/java/avro/src/main/java/org/apache/avro/JsonProperties.java
+++ b/lang/java/avro/src/main/java/org/apache/avro/JsonProperties.java
@@ -20,9 +20,12 @@ package org.apache.avro;
 import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Set;
 import java.io.IOException;
 
+import org.apache.avro.util.internal.Accessor;
+import org.apache.avro.util.internal.Accessor.JsonPropertiesAccessor;
 import org.apache.avro.util.internal.JacksonUtils;
 
 import com.fasterxml.jackson.core.JsonGenerator;
@@ -110,6 +113,16 @@ import com.fasterxml.jackson.databind.node.TextNode;
  * @see org.apache.avro.data.Json
  */
 public abstract class JsonProperties {
+
+  static {
+    Accessor.setAccessor(new JsonPropertiesAccessor() {
+      @Override
+      protected void addProp(JsonProperties props, String name, JsonNode value) {
+        props.addProp(name, value);
+      }
+    });
+  }
+
   public static class Null {
     private Null() {}
   }
@@ -136,10 +149,8 @@ public abstract class JsonProperties {
   /**
    * Returns the value of the named property in this schema.
    * Returns <tt>null</tt> if there is no property with that name.
-   * @deprecated use {@link #getObjectProp(String)}
    */
-  @Deprecated
-  public synchronized JsonNode getJsonProp(String name) {
+  synchronized JsonNode getJsonProp(String name) {
     return props.get(name);
   }
 
@@ -164,18 +175,7 @@ public abstract class JsonProperties {
     addProp(name, TextNode.valueOf(value));
   }
 
-  /**
-   * Adds a property with the given name <tt>name</tt> and
-   * value <tt>value</tt>. Neither <tt>name</tt> nor <tt>value</tt> can be
-   * <tt>null</tt>. It is illegal to add a property if another with
-   * the same name but different value already exists in this schema.
-   *
-   * @param name The name of the property to add
-   * @param value The value for the property to add
-   * @deprecated use {@link #addProp(String, Object)}
-   */
-  @Deprecated
-  public synchronized void addProp(String name, JsonNode value) {
+  synchronized void addProp(String name, JsonNode value) {
     if (reserved.contains(name))
       throw new AvroRuntimeException("Can't set reserved property: " + name);
 
@@ -193,6 +193,16 @@ public abstract class JsonProperties {
     addProp(name, JacksonUtils.toJsonNode(value));
   }
 
+  /**
+   * Adds all the props from the specified json properties.
+   *
+   * @see #getObjectProps()
+   */
+  public void addAllProps(JsonProperties properties) {
+    for (Entry<String, JsonNode> entry : properties.getJsonProps().entrySet())
+      addProp(entry.getKey(), entry.getValue());
+  }
+
   /** Return the defined properties that have string values. */
   @Deprecated public Map<String,String> getProps() {
     Map<String,String> result = new LinkedHashMap<>();
@@ -211,11 +221,10 @@ public abstract class JsonProperties {
   }
 
   /**
-   * Return the defined properties as an unmodifiable Map.
+   * Return the defined properties as an unmodifieable Map.
    * @deprecated use {@link #getObjectProps()}
    */
-  @Deprecated
-  public Map<String,JsonNode> getJsonProps() {
+  Map<String,JsonNode> getJsonProps() {
     return Collections.unmodifiableMap(props);
   }
 
diff --git a/lang/java/avro/src/main/java/org/apache/avro/Protocol.java b/lang/java/avro/src/main/java/org/apache/avro/Protocol.java
index f4a184e..c5800a7 100644
--- a/lang/java/avro/src/main/java/org/apache/avro/Protocol.java
+++ b/lang/java/avro/src/main/java/org/apache/avro/Protocol.java
@@ -231,6 +231,15 @@ public class Protocol extends JsonProperties {
     super(PROTOCOL_RESERVED);
   }
 
+  /**
+   * Constructs a similar Protocol instance with the same {@code name}, {@code doc}, and {@code namespace} as {code p}
+   * has. It also copies all the {@code props}.
+   */
+  public Protocol(Protocol p) {
+    this(p.getName(), p.getDoc(), p.getNamespace());
+    props.putAll(p.props);
+  }
+
   public Protocol(String name, String doc, String namespace) {
     super(PROTOCOL_RESERVED);
     this.name = name;
@@ -271,6 +280,12 @@ public class Protocol extends JsonProperties {
   public Message createMessage(String name, String doc, Schema request) {
     return createMessage(name, doc, new LinkedHashMap<String,String>(),request);
   }
+
+  /** Create a one-way message using the {@code name}, {@code doc}, and {@code props} of {@code m}. */
+  public Message createMessage(Message m, Schema request) {
+    return createMessage(m.getName(), m.getDoc(), m.getJsonProps(), request);
+  }
+
   /** Create a one-way message. */
   public <T> Message createMessage(String name, String doc,
                                    Map<String,T> propMap, Schema request) {
@@ -284,6 +299,12 @@ public class Protocol extends JsonProperties {
     return createMessage(name, doc, new LinkedHashMap<String,String>(),
                          request, response, errors);
   }
+
+  /** Create a two-way message using the {@code name}, {@code doc}, and {@code props} of {@code m}. */
+  public Message createMessage(Message m, Schema request, Schema response, Schema errors) {
+    return createMessage(m.getName(), m.getDoc(), m.getJsonProps(), request, response, errors);
+  }
+
   /** Create a two-way message. */
   public <T> Message createMessage(String name, String doc,
                                    Map<String,T> propMap, Schema request,
diff --git a/lang/java/avro/src/main/java/org/apache/avro/Schema.java b/lang/java/avro/src/main/java/org/apache/avro/Schema.java
index 280492c..6c63ddc 100644
--- a/lang/java/avro/src/main/java/org/apache/avro/Schema.java
+++ b/lang/java/avro/src/main/java/org/apache/avro/Schema.java
@@ -36,6 +36,8 @@ import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.avro.util.internal.Accessor;
+import org.apache.avro.util.internal.Accessor.FieldAccessor;
 import org.apache.avro.util.internal.JacksonUtils;
 
 import com.fasterxml.jackson.core.JsonFactory;
@@ -136,7 +138,7 @@ public abstract class Schema extends JsonProperties {
 
   int hashCode = NO_HASHCODE;
 
-  @Override public void addProp(String name, JsonNode value) {
+  @Override void addProp(String name, JsonNode value) {
     super.addProp(name, value);
     hashCode = NO_HASHCODE;
   }
@@ -392,6 +394,25 @@ public abstract class Schema extends JsonProperties {
   /** A field within a record. */
   public static class Field extends JsonProperties {
 
+    static {
+      Accessor.setAccessor(new FieldAccessor() {
+        @Override
+        protected JsonNode defaultValue(Field field) {
+          return field.defaultValue();
+        }
+
+        @Override
+        protected Field createField(String name, Schema schema, String doc, JsonNode defaultValue) {
+          return new Field(name, schema, doc, defaultValue);
+        }
+
+        @Override
+        protected Field createField(String name, Schema schema, String doc, JsonNode defaultValue, boolean validate, Order order) {
+          return new Field(name, schema, doc, defaultValue, validate, order);
+        }
+      });
+    }
+
     /** How values of this field should be ordered when sorting records. */
     public enum Order {
       ASCENDING, DESCENDING, IGNORE;
@@ -407,12 +428,11 @@ public abstract class Schema extends JsonProperties {
     private final Order order;
     private Set<String> aliases;
 
-    /** @deprecated use {@link #Field(String, Schema, String, Object)} */
-    @Deprecated
-    public Field(String name, Schema schema, String doc,
+    Field(String name, Schema schema, String doc,
         JsonNode defaultValue) {
       this(name, schema, doc, defaultValue, Order.ASCENDING);
     }
+
     /** @deprecated use {@link #Field(String, Schema, String, Object, Order)} */
     @Deprecated
     public Field(String name, Schema schema, String doc,
@@ -430,6 +450,18 @@ public abstract class Schema extends JsonProperties {
         : defaultValue;
       this.order = order;
     }
+
+    /**
+     * Constructs a new Field instance with the same {@code name}, {@code doc}, {@code defaultValue}, and {@code order}
+     * as {@code field} has with changing the schema to the specified one. It also copies all the {@code props} and
+     * {@code aliases}.
+     */
+    public Field(Field field, Schema schema) {
+      this(field.name, schema, field.doc, field.defaultValue, field.order);
+      props.putAll(field.props);
+      if (field.aliases != null)
+        aliases = new LinkedHashSet<String>(field.aliases);
+    }
     /**
      * @param defaultValue the default value for this field specified using the mapping
      *  in {@link JsonProperties}
@@ -453,8 +485,7 @@ public abstract class Schema extends JsonProperties {
     public Schema schema() { return schema; }
     /** Field's documentation within the record, if set. May return null. */
     public String doc() { return doc; }
-    /** @deprecated use {@link #defaultVal() } */
-    @Deprecated public JsonNode defaultValue() { return defaultValue; }
+    JsonNode defaultValue() { return defaultValue; }
     /**
      * @return the default value for this field specified using the mapping
      *  in {@link JsonProperties}
@@ -1080,8 +1111,7 @@ public abstract class Schema extends JsonProperties {
    * The contents of <tt>file</tt> is expected to be in UTF-8 format.
    * @param file  The file to read the schema from.
    * @return  The freshly built Schema.
-   * @throws IOException if there was trouble reading the contents
-   * @throws JsonParseException if the contents are invalid
+   * @throws IOException if there was trouble reading the contents or they are invalid
    * @deprecated use {@link Schema.Parser} instead.
    */
   public static Schema parse(File file) throws IOException {
@@ -1093,8 +1123,7 @@ public abstract class Schema extends JsonProperties {
    * The contents of <tt>in</tt> is expected to be in UTF-8 format.
    * @param in  The input stream to read the schema from.
    * @return  The freshly built Schema.
-   * @throws IOException if there was trouble reading the contents
-   * @throws JsonParseException if the contents are invalid
+   * @throws IOException if there was trouble reading the contents or they are invalid
    * @deprecated use {@link Schema.Parser} instead.
    */
   public static Schema parse(InputStream in) throws IOException {
@@ -1428,12 +1457,7 @@ public abstract class Schema extends JsonProperties {
     return jsonNode != null ? jsonNode.textValue() : null;
   }
 
-  /**
-   * Parses a string as Json.
-   * @deprecated use {@link org.apache.avro.data.Json#parseJson(String)}
-   */
-  @Deprecated
-  public static JsonNode parseJson(String s) {
+  static JsonNode parseJson(String s) {
     try {
       return MAPPER.readTree(FACTORY.createJsonParser(new StringReader(s)));
     } catch (JsonParseException e) {
@@ -1443,6 +1467,13 @@ public abstract class Schema extends JsonProperties {
     }
   }
 
+  /**
+   * Parses the specified json string to an object.
+   */
+  public static Object parseJsonToObject(String s) {
+    return JacksonUtils.toObject(parseJson(s));
+  }
+
   /** Rewrite a writer's schema using the aliases from a reader's schema.  This
    * permits reading records, enums and fixed schemas whose names have changed,
    * and records whose field names have changed.  The returned schema always
diff --git a/lang/java/avro/src/main/java/org/apache/avro/data/Json.java b/lang/java/avro/src/main/java/org/apache/avro/data/Json.java
index c4f75e6..09c2363 100644
--- a/lang/java/avro/src/main/java/org/apache/avro/data/Json.java
+++ b/lang/java/avro/src/main/java/org/apache/avro/data/Json.java
@@ -67,52 +67,6 @@ public class Json {
     }
   }
 
-  /**
-   * {@link DatumWriter} for arbitrary Json data.
-   * @deprecated use {@link ObjectWriter}
-   */
-  @Deprecated
-  public static class Writer implements DatumWriter<JsonNode> {
-
-    @Override public void setSchema(Schema schema) {
-      if (!SCHEMA.equals(schema))
-        throw new RuntimeException("Not the Json schema: "+schema);
-    }
-
-    @Override
-    public void write(JsonNode datum, Encoder out) throws IOException {
-      Json.write(datum, out);
-    }
-  }
-
-  /**
-   * {@link DatumReader} for arbitrary Json data.
-   * @deprecated use {@link ObjectReader}
-   */
-  @Deprecated
-  public static class Reader implements DatumReader<JsonNode> {
-    private Schema written;
-    private ResolvingDecoder resolver;
-
-    @Override public void setSchema(Schema schema) {
-      this.written = SCHEMA.equals(written) ? null : schema;
-    }
-
-    @Override
-    public JsonNode read(JsonNode reuse, Decoder in) throws IOException {
-      if (written == null)                        // same schema
-        return Json.read(in);
-
-      // use a resolver to adapt alternate version of Json schema
-      if (resolver == null)
-        resolver = DecoderFactory.get().resolvingDecoder(written, SCHEMA, null);
-      resolver.configure(in);
-      JsonNode result = Json.read(resolver);
-      resolver.drain();
-      return result;
-    }
-  }
-
   /** {@link DatumWriter} for arbitrary Json data using the object model described
    *  in {@link org.apache.avro.JsonProperties}. */
   public static class ObjectWriter implements DatumWriter<Object> {
@@ -181,10 +135,8 @@ public class Json {
 
   /**
    * Write Json data as Avro data.
-   * @deprecated internal method
    */
-  @Deprecated
-  public static void write(JsonNode node, Encoder out) throws IOException {
+  private static void write(JsonNode node, Encoder out) throws IOException {
     switch(node.asToken()) {
     case VALUE_NUMBER_INT:
       out.writeIndex(JsonType.LONG.ordinal());
@@ -240,10 +192,8 @@ public class Json {
 
   /**
    * Read Json data from Avro data.
-   * @deprecated internal method
    */
-  @Deprecated
-  public static JsonNode read(Decoder in) throws IOException {
+  private static JsonNode read(Decoder in) throws IOException {
     switch (JsonType.values()[in.readIndex()]) {
     case LONG:
       return new LongNode(in.readLong());
diff --git a/lang/java/avro/src/main/java/org/apache/avro/data/RecordBuilderBase.java b/lang/java/avro/src/main/java/org/apache/avro/data/RecordBuilderBase.java
index 8805ba5..106c500 100644
--- a/lang/java/avro/src/main/java/org/apache/avro/data/RecordBuilderBase.java
+++ b/lang/java/avro/src/main/java/org/apache/avro/data/RecordBuilderBase.java
@@ -85,7 +85,7 @@ public abstract class RecordBuilderBase<T extends IndexedRecord>
     if (isValidValue(field, value)) {
       return;
     }
-    else if (field.defaultValue() != null) {
+    else if (field.defaultVal() != null) {
       return;
     }
     else {
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 835d3a0..419cdba 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
@@ -49,10 +49,11 @@ import org.apache.avro.io.DecoderFactory;
 import org.apache.avro.io.EncoderFactory;
 import org.apache.avro.io.DatumReader;
 import org.apache.avro.io.DatumWriter;
-import org.apache.avro.io.parsing.ResolvingGrammarGenerator;
 import org.apache.avro.util.Utf8;
+import org.apache.avro.util.internal.Accessor;
 
 import com.fasterxml.jackson.databind.JsonNode;
+
 import com.google.common.collect.MapMaker;
 
 /** Utilities for generic Java data. See {@link GenericRecordBuilder} for a convenient
@@ -993,7 +994,7 @@ public class GenericData {
    */
   @SuppressWarnings({ "rawtypes", "unchecked" })
   public Object getDefaultValue(Field field) {
-    JsonNode json = field.defaultValue();
+    JsonNode json = Accessor.defaultValue(field);
     if (json == null)
       throw new AvroMissingFieldException("Field " + field
                                           + " not set and has no default value", field);
@@ -1013,7 +1014,7 @@ public class GenericData {
       try {
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         BinaryEncoder encoder = EncoderFactory.get().binaryEncoder(baos, null);
-        ResolvingGrammarGenerator.encode(encoder, field.schema(), json);
+        Accessor.encode(encoder, field.schema(), json);
         encoder.flush();
         BinaryDecoder decoder =
           DecoderFactory.get().binaryDecoder(baos.toByteArray(), null);
diff --git a/lang/java/avro/src/main/java/org/apache/avro/io/EncoderFactory.java b/lang/java/avro/src/main/java/org/apache/avro/io/EncoderFactory.java
index 52c52a6..192536c 100644
--- a/lang/java/avro/src/main/java/org/apache/avro/io/EncoderFactory.java
+++ b/lang/java/avro/src/main/java/org/apache/avro/io/EncoderFactory.java
@@ -320,10 +320,8 @@ public class EncoderFactory {
    *          The JsonGenerator to write with. Cannot be null.
    * @return A JsonEncoder configured with <i>gen</i> and <i>schema</i>
    * @throws IOException
-   * @deprecated internal method
    */
-  @Deprecated
-  public JsonEncoder jsonEncoder(Schema schema, JsonGenerator gen)
+  JsonEncoder jsonEncoder(Schema schema, JsonGenerator gen)
       throws IOException {
     return new JsonEncoder(schema, gen);
   }
diff --git a/lang/java/avro/src/main/java/org/apache/avro/io/JsonEncoder.java b/lang/java/avro/src/main/java/org/apache/avro/io/JsonEncoder.java
index 3328d9f..44657f0 100644
--- a/lang/java/avro/src/main/java/org/apache/avro/io/JsonEncoder.java
+++ b/lang/java/avro/src/main/java/org/apache/avro/io/JsonEncoder.java
@@ -131,10 +131,8 @@ public class JsonEncoder extends ParsingEncoder implements Parser.ActionHandler
    *          The JsonGenerator to direct output to. Cannot be null.
    * @throws IOException
    * @return this JsonEncoder
-   * @deprecated internal method
    */
-  @Deprecated
-  public JsonEncoder configure(JsonGenerator generator) throws IOException {
+  private JsonEncoder configure(JsonGenerator generator) throws IOException {
     if (null == generator)
       throw new NullPointerException("JsonGenerator cannot be null");
     if (null != parser) {
diff --git a/lang/java/avro/src/main/java/org/apache/avro/io/parsing/ResolvingGrammarGenerator.java b/lang/java/avro/src/main/java/org/apache/avro/io/parsing/ResolvingGrammarGenerator.java
index 47e12a9..7197882 100644
--- a/lang/java/avro/src/main/java/org/apache/avro/io/parsing/ResolvingGrammarGenerator.java
+++ b/lang/java/avro/src/main/java/org/apache/avro/io/parsing/ResolvingGrammarGenerator.java
@@ -30,6 +30,8 @@ import org.apache.avro.Schema;
 import org.apache.avro.Schema.Field;
 import org.apache.avro.io.Encoder;
 import org.apache.avro.io.EncoderFactory;
+import org.apache.avro.util.internal.Accessor;
+import org.apache.avro.util.internal.Accessor.ResolvingGrammarGeneratorAccessor;
 
 import com.fasterxml.jackson.databind.JsonNode;
 
@@ -38,6 +40,16 @@ import com.fasterxml.jackson.databind.JsonNode;
  * schemas.
  */
 public class ResolvingGrammarGenerator extends ValidatingGrammarGenerator {
+
+  static {
+    Accessor.setAccessor(new ResolvingGrammarGeneratorAccessor() {
+      @Override
+      protected void encode(Encoder e, Schema s, JsonNode n) throws IOException {
+        ResolvingGrammarGenerator.encode(e, s, n);
+      }
+    });
+  }
+
   /**
    * Resolves the writer schema <tt>writer</tt> and the reader schema
    * <tt>reader</tt> and returns the start symbol for the grammar generated.
@@ -235,7 +247,7 @@ public class ResolvingGrammarGenerator extends ValidatingGrammarGenerator {
       for (Field rf : rfields) {
         String fname = rf.name();
         if (writer.getField(fname) == null) {
-          if (rf.defaultValue() == null) {
+          if (rf.defaultVal() == null) {
             result = Symbol.error("Found " + writer.getFullName()
                                   + ", expecting " + reader.getFullName()
                                   + ", missing required field " + fname);
@@ -283,7 +295,7 @@ public class ResolvingGrammarGenerator extends ValidatingGrammarGenerator {
         String fname = rf.name();
         Field wf = writer.getField(fname);
         if (wf == null) {
-          byte[] bb = getBinary(rf.schema(), rf.defaultValue());
+          byte[] bb = getBinary(rf.schema(), Accessor.defaultValue(rf));
           production[--count] = Symbol.defaultStartAction(bb);
           production[--count] = generate(rf.schema(), rf.schema(), seen);
           production[--count] = Symbol.DEFAULT_END_ACTION;
@@ -317,10 +329,8 @@ public class ResolvingGrammarGenerator extends ValidatingGrammarGenerator {
    * @param s The schema for the object being encoded.
    * @param n The Json node to encode.
    * @throws IOException
-   * @deprecated internal method
    */
-  @Deprecated
-  public static void encode(Encoder e, Schema s, JsonNode n)
+  static void encode(Encoder e, Schema s, JsonNode n)
     throws IOException {
     switch (s.getType()) {
     case RECORD:
@@ -328,7 +338,7 @@ public class ResolvingGrammarGenerator extends ValidatingGrammarGenerator {
         String name = f.name();
         JsonNode v = n.get(name);
         if (v == null) {
-          v = f.defaultValue();
+          v = Accessor.defaultValue(f);
         }
         if (v == null) {
           throw new AvroTypeException("No default value for: " + name);
diff --git a/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectData.java b/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectData.java
index 6c59a69..d8eb2cb 100644
--- a/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectData.java
+++ b/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectData.java
@@ -38,13 +38,12 @@ import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.node.NullNode;
 import com.google.common.collect.MapMaker;
 import org.apache.avro.AvroRemoteException;
 import org.apache.avro.AvroRuntimeException;
 import org.apache.avro.AvroTypeException;
 import org.apache.avro.Conversion;
+import org.apache.avro.JsonProperties;
 import org.apache.avro.LogicalType;
 import org.apache.avro.Protocol;
 import org.apache.avro.Protocol.Message;
@@ -611,15 +610,15 @@ public class ReflectData extends SpecificData {
               Schema fieldSchema = createFieldSchema(field, names);
               AvroDefault defaultAnnotation
                 = field.getAnnotation(AvroDefault.class);
-              JsonNode defaultValue = (defaultAnnotation == null)
+              Object defaultValue = (defaultAnnotation == null)
                 ? null
-                : Schema.parseJson(defaultAnnotation.value());
+                : Schema.parseJsonToObject(defaultAnnotation.value());
 
               if (defaultValue == null
                   && fieldSchema.getType() == Schema.Type.UNION) {
                 Schema defaultType = fieldSchema.getTypes().get(0);
                 if (defaultType.getType() == Schema.Type.NULL) {
-                  defaultValue = NullNode.getInstance();
+                  defaultValue = JsonProperties.NULL_VALUE;
                 }
               }
               AvroName annotatedName = field.getAnnotation(AvroName.class);       // Rename fields
diff --git a/lang/java/avro/src/main/java/org/apache/avro/util/internal/Accessor.java b/lang/java/avro/src/main/java/org/apache/avro/util/internal/Accessor.java
new file mode 100644
index 0000000..7b39ba7
--- /dev/null
+++ b/lang/java/avro/src/main/java/org/apache/avro/util/internal/Accessor.java
@@ -0,0 +1,119 @@
+/**
+ * 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.util.internal;
+
+import java.io.IOException;
+
+import org.apache.avro.JsonProperties;
+import org.apache.avro.Schema;
+import org.apache.avro.Schema.Field;
+import org.apache.avro.Schema.Field.Order;
+import org.apache.avro.io.Encoder;
+import org.apache.avro.io.EncoderFactory;
+import org.apache.avro.io.JsonEncoder;
+import org.apache.avro.io.parsing.ResolvingGrammarGenerator;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonNode;
+
+public class Accessor {
+  public abstract static class JsonPropertiesAccessor {
+    protected abstract void addProp(JsonProperties props, String name, JsonNode value);
+  }
+
+  public abstract static class FieldAccessor {
+    protected abstract JsonNode defaultValue(Field field);
+
+    protected abstract Field createField(String name, Schema schema, String doc, JsonNode defaultValue, boolean validate, Order order);
+
+    protected abstract Field createField(String name, Schema schema, String doc, JsonNode defaultValue);
+  }
+
+  public abstract static class ResolvingGrammarGeneratorAccessor {
+    protected abstract void encode(Encoder e, Schema s, JsonNode n) throws IOException;
+  }
+
+  public abstract static class EncoderFactoryAccessor {
+    protected abstract JsonEncoder jsonEncoder(EncoderFactory factory, Schema schema, JsonGenerator gen)
+        throws IOException;
+  }
+
+  private static volatile JsonPropertiesAccessor jsonPropertiesAccessor;
+
+  private static volatile FieldAccessor fieldAccessor;
+
+  private static volatile ResolvingGrammarGeneratorAccessor resolvingGrammarGeneratorAccessor;
+
+  public static void setAccessor(JsonPropertiesAccessor accessor) {
+    if (jsonPropertiesAccessor != null)
+      throw new IllegalStateException("JsonPropertiesAccessor already initialized");
+    jsonPropertiesAccessor = accessor;
+  }
+
+  public static void setAccessor(FieldAccessor accessor) {
+    if (fieldAccessor != null)
+      throw new IllegalStateException("FieldAccessor already initialized");
+    fieldAccessor = accessor;
+  }
+
+  private static FieldAccessor fieldAccessor() {
+    if (fieldAccessor == null)
+      ensureLoaded(Field.class);
+    return fieldAccessor;
+  }
+
+  public static void setAccessor(ResolvingGrammarGeneratorAccessor accessor) {
+    if (resolvingGrammarGeneratorAccessor != null)
+      throw new IllegalStateException("ResolvingGrammarGeneratorAccessor already initialized");
+    resolvingGrammarGeneratorAccessor = accessor;
+  }
+
+  private static ResolvingGrammarGeneratorAccessor resolvingGrammarGeneratorAccessor() {
+    if (resolvingGrammarGeneratorAccessor == null)
+      ensureLoaded(ResolvingGrammarGenerator.class);
+    return resolvingGrammarGeneratorAccessor;
+  }
+
+  private static void ensureLoaded(Class<?> c) {
+    try {
+      Class.forName(c.getName());
+    } catch (ClassNotFoundException e) {
+      // Shall never happen as the class is specified by its Class instance
+    }
+  }
+
+  public static void addProp(JsonProperties props, String name, JsonNode value) {
+    jsonPropertiesAccessor.addProp(props, name, value);
+  }
+
+  public static JsonNode defaultValue(Field field) {
+    return fieldAccessor.defaultValue(field);
+  }
+
+  public static void encode(Encoder e, Schema s, JsonNode n) throws IOException {
+    resolvingGrammarGeneratorAccessor().encode(e, s, n);
+  }
+
+  public static Field createField(String name, Schema schema, String doc, JsonNode defaultValue, boolean validate, Order order) {
+    return fieldAccessor().createField(name, schema, doc, defaultValue, validate, order);
+  }
+
+  public static Field createField(String name, Schema schema, String doc, JsonNode defaultValue) {
+    return fieldAccessor().createField(name, schema, doc, defaultValue);
+  }
+
+}
diff --git a/lang/java/avro/src/test/java/org/apache/avro/reflect/TestReflect.java b/lang/java/avro/src/test/java/org/apache/avro/reflect/TestReflect.java
index cb572f0..85debac 100644
--- a/lang/java/avro/src/test/java/org/apache/avro/reflect/TestReflect.java
+++ b/lang/java/avro/src/test/java/org/apache/avro/reflect/TestReflect.java
@@ -37,6 +37,7 @@ import java.util.Random;
 
 import org.apache.avro.AvroRuntimeException;
 import org.apache.avro.AvroTypeException;
+import org.apache.avro.JsonProperties;
 import org.apache.avro.Protocol;
 import org.apache.avro.Schema;
 import org.apache.avro.SchemaBuilder;
@@ -389,7 +390,7 @@ public class TestReflect {
     Schema r11Record = ReflectData.get().getSchema(R11.class);
     assertEquals(Schema.Type.RECORD, r11Record.getType());
     Field r11Field = r11Record.getField("text");
-    assertEquals(NullNode.getInstance(), r11Field.defaultValue());
+    assertEquals(JsonProperties.NULL_VALUE, r11Field.defaultVal());
     Schema r11FieldSchema = r11Field.schema();
     assertEquals(Schema.Type.UNION, r11FieldSchema.getType());
     assertEquals(Schema.Type.NULL, r11FieldSchema.getTypes().get(0).getType());
diff --git a/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java b/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java
index 5470037..aa7c5c3 100644
--- a/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java
+++ b/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java
@@ -40,7 +40,6 @@ import org.apache.avro.LogicalTypes;
 import org.apache.avro.data.Jsr310TimeConversions;
 import org.apache.avro.data.TimeConversions;
 import org.apache.avro.specific.SpecificData;
-import com.fasterxml.jackson.databind.JsonNode;
 
 import org.apache.avro.Protocol;
 import org.apache.avro.Protocol.Message;
@@ -545,9 +544,9 @@ public class SpecificCompiler {
     Protocol newP = new Protocol(p.getName(), p.getDoc(), p.getNamespace());
     Map<Schema,Schema> types = new LinkedHashMap<>();
 
-    // Copy properties
-    for (Map.Entry<String,JsonNode> prop : p.getJsonProps().entrySet())
-      newP.addProp(prop.getKey(), prop.getValue());   // copy props
+    for (Map.Entry<String, Object> a : p.getObjectProps().entrySet()) {
+      newP.addProp(a.getKey(), a.getValue());
+    }
 
     // annotate types
     Collection<Schema> namedTypes = new LinkedHashSet<>();
@@ -559,9 +558,9 @@ public class SpecificCompiler {
     Map<String,Message> newM = newP.getMessages();
     for (Message m : p.getMessages().values())
       newM.put(m.getName(), m.isOneWay()
-               ? newP.createMessage(m.getName(), m.getDoc(), m.getJsonProps(),
+               ? newP.createMessage(m,
                                     addStringType(m.getRequest(), types))
-               : newP.createMessage(m.getName(), m.getDoc(), m.getJsonProps(),
+               : newP.createMessage(m,
                                     addStringType(m.getRequest(), types),
                                     addStringType(m.getResponse(), types),
                                     addStringType(m.getErrors(), types)));
@@ -592,12 +591,7 @@ public class SpecificCompiler {
       List<Field> newFields = new ArrayList<>();
       for (Field f : s.getFields()) {
         Schema fSchema = addStringType(f.schema(), seen);
-        Field newF =
-          new Field(f.name(), fSchema, f.doc(), f.defaultValue(), f.order());
-        for (Map.Entry<String,JsonNode> p : f.getJsonProps().entrySet())
-          newF.addProp(p.getKey(), p.getValue()); // copy props
-        for (String a : f.aliases())
-          newF.addAlias(a);                       // copy aliases
+        Field newF = new Field(f, fSchema);
         newFields.add(newF);
       }
       result.setFields(newFields);
@@ -618,8 +612,7 @@ public class SpecificCompiler {
       result = Schema.createUnion(types);
       break;
     }
-    for (Map.Entry<String,JsonNode> p : s.getJsonProps().entrySet())
-      result.addProp(p.getKey(), p.getValue());   // copy props
+    result.addAllProps(s);
     seen.put(s, result);
     return result;
   }
@@ -640,14 +633,17 @@ public class SpecificCompiler {
     default:
       throw new IllegalArgumentException("Can't check string-type of non-string/map type: " + s);
     }
-    JsonNode override = s.getJsonProp(prop);
-    if (override != null) return override.textValue();
+    return getStringType(s.getObjectProp(prop));
+  }
+  private String getStringType(Object overrideClassProperty) {
+    if (overrideClassProperty != null)
+      return overrideClassProperty.toString();
     switch (stringType) {
     case String:        return "java.lang.String";
     case Utf8:          return "org.apache.avro.util.Utf8";
     case CharSequence:  return "java.lang.CharSequence";
     default: throw new RuntimeException("Unknown string type: "+stringType);
-   }
+    }
   }
 
   /** Utility for template use.  Returns true iff a STRING-schema or
@@ -685,14 +681,15 @@ public class SpecificCompiler {
       return "java.util.List<" + javaType(schema.getElementType()) + ">";
     case MAP:
       return "java.util.Map<"
-        + getStringType(schema)+ "," + javaType(schema.getValueType()) + ">";
+        + getStringType(schema.getObjectProp(SpecificData.KEY_CLASS_PROP))+","
+        + javaType(schema.getValueType()) + ">";
     case UNION:
       List<Schema> types = schema.getTypes(); // elide unions with null
       if ((types.size() == 2) && types.contains(NULL_SCHEMA))
         return javaType(types.get(types.get(0).equals(NULL_SCHEMA) ? 1 : 0));
       return "java.lang.Object";
     case STRING:
-      return getStringType(schema);
+      return getStringType(schema.getObjectProp(SpecificData.CLASS_PROP));
     case BYTES:   return "java.nio.ByteBuffer";
     case INT:     return "java.lang.Integer";
     case LONG:    return "java.lang.Long";
@@ -814,17 +811,17 @@ public class SpecificCompiler {
 
   /** Utility for template use.  Returns the java annotations for a schema. */
   public String[] javaAnnotations(JsonProperties props) {
-    JsonNode value = props.getJsonProp("javaAnnotation");
+    Object value = props.getObjectProp("javaAnnotation");
     if (value == null)
       return new String[0];
-    if (value.isTextual())
-      return new String[] { value.textValue() };
-    if (value.isArray()) {
-      int i = 0;
-      String[] result = new String[value.size()];
-      for (JsonNode v : value)
-        result[i++] = v.textValue();
-      return result;
+    if (value instanceof String)
+      return new String[] { value.toString() };
+    if (value instanceof List) {
+      List<?> list = (List<?>) value;
+      List<String> annots = new ArrayList<String>();
+      for (Object o : list)
+        annots.add(o.toString());
+      return annots.toArray(new String[annots.size()]);
     }
     return new String[0];
   }
diff --git a/lang/java/compiler/src/main/javacc/org/apache/avro/compiler/idl/idl.jj b/lang/java/compiler/src/main/javacc/org/apache/avro/compiler/idl/idl.jj
index 69fd8c5..258dd47 100644
--- a/lang/java/compiler/src/main/javacc/org/apache/avro/compiler/idl/idl.jj
+++ b/lang/java/compiler/src/main/javacc/org/apache/avro/compiler/idl/idl.jj
@@ -73,6 +73,7 @@ import org.apache.avro.LogicalTypes;
 import org.apache.avro.Schema.*;
 import org.apache.avro.Protocol;
 import org.apache.avro.Protocol.*;
+import org.apache.avro.util.internal.Accessor;
 
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.node.*;
@@ -1010,7 +1011,7 @@ Protocol CompilationUnit():
 /*
  * Declaration syntax follows.
  */
-Schema NamedSchemaDeclaration(Map<String, JsonNode> props):
+private Schema NamedSchemaDeclaration(Map<String, JsonNode> props):
 {
   Schema s;
   String savedSpace = this.namespace;
@@ -1034,7 +1035,7 @@ Schema NamedSchemaDeclaration(Map<String, JsonNode> props):
        for (String alias : getTextProps("aliases", props, token))
          s.addAlias(alias);
      } else {                                     // add all other props
-       s.addProp(key, props.get(key));
+       Accessor.addProp(s, key, props.get(key));
      }
 
    return s;
@@ -1085,7 +1086,7 @@ Protocol ProtocolDeclaration():
    for (String key : props.keySet())
      if ("namespace".equals(key)) {               // already handled: ignore
      } else {                                     // add all other props
-       p.addProp(key, props.get(key));
+       Accessor.addProp(p, key, props.get(key));
      }
  }
  ProtocolBody(p)
@@ -1275,7 +1276,7 @@ Schema RecordDeclaration():
   }
 }
 
-void SchemaProperty(Map<String, JsonNode> properties):
+private void SchemaProperty(Map<String, JsonNode> properties):
 {
   String key;
   JsonNode val;
@@ -1305,7 +1306,7 @@ void FieldDeclaration(List<Field> fields):
   ";"
   {
     for (String key : props.keySet())
-      type.addProp(key, props.get(key));
+      Accessor.addProp(type, key, props.get(key));
   }
 }
 
@@ -1327,15 +1328,16 @@ void VariableDeclarator(Schema type, List<Field> fields):
     for (String key : props.keySet())
       if ("order".equals(key))
         order = Field.Order.valueOf(getTextProp(key,props,token).toUpperCase());
+
     boolean validate = !SchemaResolver.isUnresolvedSchema(type);
-    Field field = new Field(name,type, getDoc(), defaultValue, validate, order);
+    Field field = Accessor.createField(name, type, getDoc(), defaultValue, validate, order);
     for (String key : props.keySet())
       if ("order".equals(key)) {                  // already handled: ignore
       } else if ("aliases".equals(key)) {         // aliases
         for (String alias : getTextProps("aliases", props, token))
           field.addAlias(alias);
       } else {                                    // add all other props
-        field.addProp(key, props.get(key));
+        Accessor.addProp(field, key, props.get(key));
       }
     fields.add(field);
   }
@@ -1351,7 +1353,7 @@ String MessageDocumentation():
    }
 }
 
-Message MessageDeclaration(Protocol p, Map<String, JsonNode> props):
+private Message MessageDeclaration(Protocol p, Map<String, JsonNode> props):
 {
   String msgDoc;
   String name;
@@ -1427,7 +1429,7 @@ Schema Type():
   )
   {
     for (String key : props.keySet())
-      s.addProp(key, props.get(key));
+      Accessor.addProp(s, key, props.get(key));
     return s;
   }
 }
@@ -1585,7 +1587,7 @@ Token AnyIdentifier():
   }
 }
 
-JsonNode Json() :
+private JsonNode Json() :
 { String s; Token t; JsonNode n; }
 { 
 ( s = JsonString() { n = new TextNode(s); }
@@ -1610,7 +1612,7 @@ String JsonString() :
   }
 }
 
-JsonNode JsonObject() :
+private JsonNode JsonObject() :
 { 
   ObjectNode o = FACTORY.objectNode();
 }
@@ -1619,13 +1621,13 @@ JsonNode JsonObject() :
   { return o; }
 }
 
-void JsonFields(ObjectNode o) :
+private void JsonFields(ObjectNode o) :
 {}
 {
   JsonPair(o) [ "," JsonFields(o) ]
 }
 
-void JsonPair(ObjectNode o) :
+private void JsonPair(ObjectNode o) :
 {
   String name;
   JsonNode value;
@@ -1635,14 +1637,14 @@ void JsonPair(ObjectNode o) :
     { o.put(name, value); } 
 }
 
-JsonNode JsonArray() :
+private JsonNode JsonArray() :
 { ArrayNode a = FACTORY.arrayNode(); }
 {
   <LBRACK> [ JsonElements(a) ] <RBRACK>
     { return a; }
 }
 
-void JsonElements(ArrayNode a) :
+private void JsonElements(ArrayNode a) :
 { JsonNode element; }
 {
   element=Json() { a.add(element); } [ "," JsonElements(a) ]
diff --git a/lang/java/protobuf/src/main/java/org/apache/avro/protobuf/ProtobufData.java b/lang/java/protobuf/src/main/java/org/apache/avro/protobuf/ProtobufData.java
index 7f9ae4e..c725ca0 100644
--- a/lang/java/protobuf/src/main/java/org/apache/avro/protobuf/ProtobufData.java
+++ b/lang/java/protobuf/src/main/java/org/apache/avro/protobuf/ProtobufData.java
@@ -46,6 +46,7 @@ import com.google.protobuf.Descriptors.FileDescriptor;
 import com.google.protobuf.DescriptorProtos.FileOptions;
 
 import org.apache.avro.util.ClassUtils;
+import org.apache.avro.util.internal.Accessor;
 import com.fasterxml.jackson.core.JsonFactory;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
@@ -213,7 +214,7 @@ public class ProtobufData extends GenericData {
 
       List<Field> fields = new ArrayList<>();
       for (FieldDescriptor f : descriptor.getFields())
-        fields.add(new Field(f.getName(), getSchema(f), null, getDefault(f)));
+        fields.add(Accessor.createField(f.getName(), getSchema(f), null, getDefault(f)));
       result.setFields(fields);
       return result;
 
diff --git a/lang/java/tools/src/main/java/org/apache/avro/tool/RpcSendTool.java b/lang/java/tools/src/main/java/org/apache/avro/tool/RpcSendTool.java
index 8582a91..5db620b 100644
--- a/lang/java/tools/src/main/java/org/apache/avro/tool/RpcSendTool.java
+++ b/lang/java/tools/src/main/java/org/apache/avro/tool/RpcSendTool.java
@@ -34,13 +34,10 @@ import org.apache.avro.Protocol.Message;
 import org.apache.avro.generic.GenericDatumWriter;
 import org.apache.avro.io.DatumWriter;
 import org.apache.avro.io.EncoderFactory;
+import org.apache.avro.io.JsonEncoder;
 import org.apache.avro.ipc.Ipc;
 import org.apache.avro.ipc.generic.GenericRequestor;
 
-import com.fasterxml.jackson.core.JsonEncoding;
-import com.fasterxml.jackson.core.JsonFactory;
-import com.fasterxml.jackson.core.JsonGenerator;
-
 /**
  * Sends a single RPC message.
  */
@@ -106,11 +103,9 @@ public class RpcSendTool implements Tool {
   private void dumpJson(PrintStream out, Schema schema, Object datum)
   throws IOException {
     DatumWriter<Object> writer = new GenericDatumWriter<>(schema);
-    JsonGenerator g =
-      new JsonFactory().createJsonGenerator(out, JsonEncoding.UTF8);
-    g.useDefaultPrettyPrinter();
-    writer.write(datum, EncoderFactory.get().jsonEncoder(schema, g));
-    g.flush();
+    JsonEncoder jsonEncoder = EncoderFactory.get().jsonEncoder(schema, out, true);
+    writer.write(datum, jsonEncoder);
+    jsonEncoder.flush();
     out.println();
     out.flush();
   }
diff --git a/lang/java/trevni/avro/src/test/java/org/apache/trevni/avro/RandomData.java b/lang/java/trevni/avro/src/test/java/org/apache/trevni/avro/RandomData.java
index 227549a..2426d89 100644
--- a/lang/java/trevni/avro/src/test/java/org/apache/trevni/avro/RandomData.java
+++ b/lang/java/trevni/avro/src/test/java/org/apache/trevni/avro/RandomData.java
@@ -64,7 +64,7 @@ public class RandomData implements Iterable<Object> {
     case RECORD:
       GenericRecord record = new GenericData.Record(schema);
       for (Schema.Field field : schema.getFields()) {
-        Object value = (field.getJsonProp(USE_DEFAULT) == null)
+        Object value = (field.getObjectProp(USE_DEFAULT) == null)
           ? generate(field.schema(), random, d+1)
           : GenericData.get().getDefaultValue(field);
         record.put(field.name(), value);