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 fa1a8ef [AVRO-2369] Add a way to specify a null default for unions
with a null.
fa1a8ef is described below
commit fa1a8ef805111c4bb0d6e5fc59e635cf72d33d14
Author: Daniel Kulp <[email protected]>
AuthorDate: Fri Apr 5 15:04:57 2019 -0400
[AVRO-2369] Add a way to specify a null default for unions with a null.
---
.../src/main/java/org/apache/avro/Protocol.java | 6 +-
.../avro/src/main/java/org/apache/avro/Schema.java | 48 +++--
.../main/java/org/apache/avro/SchemaBuilder.java | 217 +++++++++++----------
.../org/apache/avro/TestCircularReferences.java | 10 +-
.../java/org/apache/avro/TestSchemaBuilder.java | 19 +-
.../avro/file/TestSeekableByteArrayInput.java | 2 +-
6 files changed, 166 insertions(+), 136 deletions(-)
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 71f8548..a2f3a7c 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
@@ -35,6 +35,7 @@ import java.util.Set;
import java.util.HashSet;
import org.apache.avro.Schema.Field;
+import org.apache.avro.Schema.Field.Order;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
@@ -404,7 +405,7 @@ public class Protocol extends JsonProperties {
/**
* Render this as <a href="http://json.org/">JSON</a>.
- *
+ *
* @param pretty if true, pretty-print JSON.
*/
public String toString(boolean pretty) {
@@ -587,7 +588,8 @@ public class Protocol extends JsonProperties {
JsonNode fieldDocNode = field.get("doc");
if (fieldDocNode != null)
fieldDoc = fieldDocNode.textValue();
- Field newField = new Field(name, Schema.parse(fieldTypeNode, types),
fieldDoc, field.get("default"));
+ Field newField = new Field(name, Schema.parse(fieldTypeNode, types),
fieldDoc, field.get("default"), true,
+ Order.ASCENDING);
Set<String> aliases = Schema.parseAliases(field);
if (aliases != null) { // add aliases
for (String alias : aliases)
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 374917c..587634d 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
@@ -24,6 +24,8 @@ import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.DoubleNode;
+import com.fasterxml.jackson.databind.node.NullNode;
+
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@@ -448,7 +450,7 @@ public abstract class Schema extends JsonProperties {
@Override
protected Field createField(String name, Schema schema, String doc,
JsonNode defaultValue) {
- return new Field(name, schema, doc, defaultValue);
+ return new Field(name, schema, doc, defaultValue, true,
Order.ASCENDING);
}
@Override
@@ -469,6 +471,12 @@ public abstract class Schema extends JsonProperties {
}
};
+ /**
+ * For Schema unions with a "null" type as the first entry, this can be
used to
+ * specify that the default for the union is null.
+ */
+ public static final Object NULL_DEFAULT_VALUE = new Object();
+
private final String name; // name of the field.
private int position = -1;
private final Schema schema;
@@ -477,21 +485,13 @@ public abstract class Schema extends JsonProperties {
private final Order order;
private Set<String> aliases;
- Field(String name, Schema schema, String doc, JsonNode defaultValue) {
- this(name, schema, doc, defaultValue, true, Order.ASCENDING);
- }
-
- Field(String name, Schema schema, String doc, JsonNode defaultValue, Order
order) {
- this(name, schema, doc, defaultValue, true, order);
- }
-
Field(String name, Schema schema, String doc, JsonNode defaultValue,
boolean validateDefault, Order order) {
super(FIELD_RESERVED);
this.name = validateName(name);
this.schema = schema;
this.doc = doc;
this.defaultValue = validateDefault ? validateDefault(name, schema,
defaultValue) : defaultValue;
- this.order = order;
+ this.order = Objects.requireNonNull(order, "Order cannot be null");
}
/**
@@ -501,18 +501,34 @@ public abstract class Schema extends JsonProperties {
* {@code aliases}.
*/
public Field(Field field, Schema schema) {
- this(field.name, schema, field.doc, field.defaultValue, field.order);
+ this(field.name, schema, field.doc, field.defaultValue, true,
field.order);
putAll(field);
if (field.aliases != null)
aliases = new LinkedHashSet<>(field.aliases);
}
/**
+ *
+ */
+ public Field(String name, Schema schema) {
+ this(name, schema, (String) null, (JsonNode) null, true,
Order.ASCENDING);
+ }
+
+ /**
+ *
+ */
+ public Field(String name, Schema schema, String doc) {
+ this(name, schema, doc, (JsonNode) null, true, Order.ASCENDING);
+ }
+
+ /**
* @param defaultValue the default value for this field specified using the
* mapping in {@link JsonProperties}
*/
public Field(String name, Schema schema, String doc, Object defaultValue) {
- this(name, schema, doc, defaultValue, Order.ASCENDING);
+ this(name, schema, doc,
+ defaultValue == NULL_DEFAULT_VALUE ? NullNode.getInstance() :
JacksonUtils.toJsonNode(defaultValue), true,
+ Order.ASCENDING);
}
/**
@@ -520,7 +536,9 @@ public abstract class Schema extends JsonProperties {
* mapping in {@link JsonProperties}
*/
public Field(String name, Schema schema, String doc, Object defaultValue,
Order order) {
- this(name, schema, doc, JacksonUtils.toJsonNode(defaultValue), order);
+ this(name, schema, doc,
+ defaultValue == NULL_DEFAULT_VALUE ? NullNode.getInstance() :
JacksonUtils.toJsonNode(defaultValue), true,
+ Objects.requireNonNull(order));
}
public String name() {
@@ -1595,7 +1613,7 @@ public abstract class Schema extends JsonProperties {
&& (Type.FLOAT.equals(fieldSchema.getType()) ||
Type.DOUBLE.equals(fieldSchema.getType()))
&& defaultValue.isTextual())
defaultValue = new
DoubleNode(Double.valueOf(defaultValue.textValue()));
- Field f = new Field(fieldName, fieldSchema, fieldDoc, defaultValue,
order);
+ Field f = new Field(fieldName, fieldSchema, fieldDoc, defaultValue,
true, order);
Iterator<String> i = field.fieldNames();
while (i.hasNext()) { // add field props
String prop = i.next();
@@ -1768,7 +1786,7 @@ public abstract class Schema extends JsonProperties {
for (Field f : s.getFields()) {
Schema fSchema = applyAliases(f.schema, seen, aliases, fieldAliases);
String fName = getFieldAlias(name, f.name, fieldAliases);
- Field newF = new Field(fName, fSchema, f.doc, f.defaultValue, f.order);
+ Field newF = new Field(fName, fSchema, f.doc, f.defaultValue, true,
f.order);
newF.putAll(f); // copy props
newFields.add(newF);
}
diff --git a/lang/java/avro/src/main/java/org/apache/avro/SchemaBuilder.java
b/lang/java/avro/src/main/java/org/apache/avro/SchemaBuilder.java
index bb851d5..20b543b 100644
--- a/lang/java/avro/src/main/java/org/apache/avro/SchemaBuilder.java
+++ b/lang/java/avro/src/main/java/org/apache/avro/SchemaBuilder.java
@@ -36,6 +36,7 @@ import org.apache.avro.util.internal.JacksonUtils;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.NullNode;
import com.fasterxml.jackson.databind.node.TextNode;
/**
@@ -77,11 +78,11 @@ import com.fasterxml.jackson.databind.node.TextNode;
* <p/>
* <h6>Selecting and Building an Avro Type</h6> The API analogy for the right
* hand side of the Avro Schema JSON
- *
+ *
* <pre>
* "type":
* </pre>
- *
+ *
* is a {@link TypeBuilder}, {@link FieldTypeBuilder}, or
* {@link UnionFieldTypeBuilder}, depending on the context. These types all
* share a similar API for selecting and building types.
@@ -89,22 +90,22 @@ import com.fasterxml.jackson.databind.node.TextNode;
* <h5>Primitive Types</h5> All Avro primitive types are trivial to configure.
A
* primitive type in Avro JSON can be declared two ways, one that supports
* custom properties and one that does not:
- *
+ *
* <pre>
* {"type":"int"}
* {"type":{"name":"int"}}
* {"type":{"name":"int", "customProp":"val"}}
* </pre>
- *
+ *
* The analogous code form for the above three JSON lines are the below three
* lines:
- *
+ *
* <pre>
* .intType()
* .intBuilder().endInt()
* .intBuilder().prop("customProp", "val").endInt()
* </pre>
- *
+ *
* Every primitive type has a shortcut to create the trivial type, and a
builder
* when custom properties are required. The first line above is a shortcut for
* the second, analogous to the JSON case.
@@ -123,7 +124,7 @@ import com.fasterxml.jackson.databind.node.TextNode;
* <li>{@link EnumBuilder#symbols(String...)}</li>
* <li>{@link RecordBuilder#fields()}</li> Example use of a named type with all
* optional parameters:
- *
+ *
* <pre>
* .enumeration("Suit").namespace("org.apache.test")
* .aliases("org.apache.test.OldSuit")
@@ -131,9 +132,9 @@ import com.fasterxml.jackson.databind.node.TextNode;
* .prop("customProp", "val")
* .symbols("SPADES", "HEARTS", "DIAMONDS", "CLUBS")
* </pre>
- *
+ *
* Which is equivalent to the JSON:
- *
+ *
* <pre>
* { "type":"enum",
* "name":"Suit", "namespace":"org.apache.test",
@@ -143,7 +144,7 @@ import com.fasterxml.jackson.databind.node.TextNode;
* "symbols":["SPADES", "HEARTS", "DIAMONDS", "CLUBS"]
* }
* </pre>
- *
+ *
* <h6>Nested Types</h6> The Avro nested types, map and array, can have custom
* properties like all avro types, are not named, and must specify a nested
* type. After configuration of optional properties, an array or map builds or
@@ -170,16 +171,16 @@ import com.fasterxml.jackson.databind.node.TextNode;
* <h6>Unions</h6> Union types are built via {@link TypeBuilder#unionOf()} or
* {@link FieldTypeBuilder#unionOf()} in the context of type selection. This
* chains together multiple types, in union order. For example:
- *
+ *
* <pre>
* .unionOf()
* .fixed("IPv4").size(4).and()
* .fixed("IPv6").size(16).and()
* .nullType().endUnion()
* </pre>
- *
+ *
* is equivalent to the Avro schema JSON:
- *
+ *
* <pre>
* [
* {"type":"fixed", "name":"IPv4", "size":4},
@@ -187,21 +188,21 @@ import com.fasterxml.jackson.databind.node.TextNode;
* "null"
* ]
* </pre>
- *
+ *
* In a field context, the first type of a union defines what default type is
* allowed.
* </p>
* Unions have two shortcuts for common cases. nullable() creates a union of a
* type and null. In a field type context, optional() is available and creates
a
* union of null and a type, with a null default. The below two are equivalent:
- *
+ *
* <pre>
* .unionOf().intType().and().nullType().endUnion()
* .nullable().intType()
* </pre>
- *
+ *
* The below two field declarations are equivalent:
- *
+ *
* <pre>
*
.name("f").type().unionOf().nullType().and().longType().endUnion().nullDefault()
* .name("f").type().optional().longType()
@@ -209,13 +210,13 @@ import com.fasterxml.jackson.databind.node.TextNode;
*
* <h6>Explicit Types and Types by Name</h6> Types can also be specified
* explicitly by passing in a Schema, or by name:
- *
+ *
* <pre>
* .type(Schema.create(Schema.Type.INT)) // explicitly specified
* .type("MD5") // reference by full name or short name
* .type("MD5", "org.apache.avro.test") // reference by name and namespace
* </pre>
- *
+ *
* When a type is specified by name, and the namespace is absent or null, the
* namespace is inherited from the enclosing context. A namespace will
propagate
* as a default to child fields, nested types, or later defined types in a
@@ -249,11 +250,11 @@ public class SchemaBuilder {
/**
* Create a builder for an Avro record with the specified name. This is
* equivalent to:
- *
+ *
* <pre>
* builder().record(name);
* </pre>
- *
+ *
* @param name the record name
*/
public static RecordBuilder<Schema> record(String name) {
@@ -263,11 +264,11 @@ public class SchemaBuilder {
/**
* Create a builder for an Avro enum with the specified name and symbols
* (values). This is equivalent to:
- *
+ *
* <pre>
* builder().enumeration(name);
* </pre>
- *
+ *
* @param name the enum name
*/
public static EnumBuilder<Schema> enumeration(String name) {
@@ -277,11 +278,11 @@ public class SchemaBuilder {
/**
* Create a builder for an Avro fixed type with the specified name and size.
* This is equivalent to:
- *
+ *
* <pre>
* builder().fixed(name);
* </pre>
- *
+ *
* @param name the fixed name
*/
public static FixedBuilder<Schema> fixed(String name) {
@@ -290,7 +291,7 @@ public class SchemaBuilder {
/**
* Create a builder for an Avro array This is equivalent to:
- *
+ *
* <pre>
* builder().array();
* </pre>
@@ -301,7 +302,7 @@ public class SchemaBuilder {
/**
* Create a builder for an Avro map This is equivalent to:
- *
+ *
* <pre>
* builder().map();
* </pre>
@@ -312,7 +313,7 @@ public class SchemaBuilder {
/**
* Create a builder for an Avro union This is equivalent to:
- *
+ *
* <pre>
* builder().unionOf();
* </pre>
@@ -323,17 +324,17 @@ public class SchemaBuilder {
/**
* Create a builder for a union of a type and null. This is a shortcut for:
- *
+ *
* <pre>
* builder().nullable();
* </pre>
- *
+ *
* and the following two lines are equivalent:
- *
+ *
* <pre>
* nullable().intType();
* </pre>
- *
+ *
* <pre>
* unionOf().intType().and().nullType().endUnion();
* </pre>
@@ -1015,7 +1016,7 @@ public class SchemaBuilder {
/**
* A plain boolean type without custom properties. This is equivalent to:
- *
+ *
* <pre>
* booleanBuilder().endBoolean();
* </pre>
@@ -1034,7 +1035,7 @@ public class SchemaBuilder {
/**
* A plain int type without custom properties. This is equivalent to:
- *
+ *
* <pre>
* intBuilder().endInt();
* </pre>
@@ -1053,7 +1054,7 @@ public class SchemaBuilder {
/**
* A plain long type without custom properties. This is equivalent to:
- *
+ *
* <pre>
* longBuilder().endLong();
* </pre>
@@ -1072,7 +1073,7 @@ public class SchemaBuilder {
/**
* A plain float type without custom properties. This is equivalent to:
- *
+ *
* <pre>
* floatBuilder().endFloat();
* </pre>
@@ -1091,7 +1092,7 @@ public class SchemaBuilder {
/**
* A plain double type without custom properties. This is equivalent to:
- *
+ *
* <pre>
* doubleBuilder().endDouble();
* </pre>
@@ -1110,7 +1111,7 @@ public class SchemaBuilder {
/**
* A plain string type without custom properties. This is equivalent to:
- *
+ *
* <pre>
* stringBuilder().endString();
* </pre>
@@ -1129,7 +1130,7 @@ public class SchemaBuilder {
/**
* A plain bytes type without custom properties. This is equivalent to:
- *
+ *
* <pre>
* bytesBuilder().endBytes();
* </pre>
@@ -1148,7 +1149,7 @@ public class SchemaBuilder {
/**
* A plain null type without custom properties. This is equivalent to:
- *
+ *
* <pre>
* nullBuilder().endNull();
* </pre>
@@ -1167,13 +1168,13 @@ public class SchemaBuilder {
/**
* Build an Avro map type Example usage:
- *
+ *
* <pre>
* map().values().intType()
* </pre>
- *
+ *
* Equivalent to Avro JSON Schema:
- *
+ *
* <pre>
* {"type":"map", "values":"int"}
* </pre>
@@ -1184,13 +1185,13 @@ public class SchemaBuilder {
/**
* Build an Avro array type Example usage:
- *
+ *
* <pre>
* array().items().longType()
* </pre>
- *
+ *
* Equivalent to Avro JSON Schema:
- *
+ *
* <pre>
* {"type":"array", "values":"long"}
* </pre>
@@ -1201,13 +1202,13 @@ public class SchemaBuilder {
/**
* Build an Avro fixed type. Example usage:
- *
+ *
* <pre>
* fixed("com.foo.IPv4").size(4)
* </pre>
- *
+ *
* Equivalent to Avro JSON Schema:
- *
+ *
* <pre>
* {"type":"fixed", "name":"com.foo.IPv4", "size":4}
* </pre>
@@ -1218,14 +1219,14 @@ public class SchemaBuilder {
/**
* Build an Avro enum type. Example usage:
- *
+ *
* <pre>
* enumeration("Suits").namespace("org.cards").doc("card suit
names").defaultSymbol("HEART").symbols("HEART", "SPADE",
* "DIAMOND", "CLUB")
* </pre>
- *
+ *
* Equivalent to Avro JSON Schema:
- *
+ *
* <pre>
* {"type":"enum", "name":"Suits", "namespace":"org.cards",
* "doc":"card suit names", "symbols":[
@@ -1238,14 +1239,14 @@ public class SchemaBuilder {
/**
* Build an Avro record type. Example usage:
- *
+ *
* <pre>
*
record("com.foo.Foo").fields().name("field1").typeInt().intDefault(1).name("field2").typeString().noDefault()
* .name("field3").optional().typeFixed("FooFixed").size(4).endRecord()
* </pre>
- *
+ *
* Equivalent to Avro JSON Schema:
- *
+ *
* <pre>
* {"type":"record", "name":"com.foo.Foo", "fields": [
* {"name":"field1", "type":"int", "default":1},
@@ -1262,7 +1263,7 @@ public class SchemaBuilder {
/**
* Build an Avro union schema type. Example usage:
- *
+ *
* <pre>
* unionOf().stringType().and().bytesType().endUnion()
* </pre>
@@ -1275,11 +1276,11 @@ public class SchemaBuilder {
* A shortcut for building a union of a type and null.
* <p/>
* For example, the code snippets below are equivalent:
- *
+ *
* <pre>
* nullable().booleanType()
* </pre>
- *
+ *
* <pre>
* unionOf().booleanType().and().nullType().endUnion()
* </pre>
@@ -1334,13 +1335,13 @@ public class SchemaBuilder {
* configuring a default for the field.
* <p/>
* For example, an int field with default value 1:
- *
+ *
* <pre>
* intSimple().withDefault(1);
* </pre>
- *
+ *
* or an array with items that are optional int types:
- *
+ *
* <pre>
* array().items().optional().intType();
* </pre>
@@ -1358,7 +1359,7 @@ public class SchemaBuilder {
/**
* A plain boolean type without custom properties. This is equivalent to:
- *
+ *
* <pre>
* booleanBuilder().endBoolean();
* </pre>
@@ -1377,7 +1378,7 @@ public class SchemaBuilder {
/**
* A plain int type without custom properties. This is equivalent to:
- *
+ *
* <pre>
* intBuilder().endInt();
* </pre>
@@ -1396,7 +1397,7 @@ public class SchemaBuilder {
/**
* A plain long type without custom properties. This is equivalent to:
- *
+ *
* <pre>
* longBuilder().endLong();
* </pre>
@@ -1415,7 +1416,7 @@ public class SchemaBuilder {
/**
* A plain float type without custom properties. This is equivalent to:
- *
+ *
* <pre>
* floatBuilder().endFloat();
* </pre>
@@ -1434,7 +1435,7 @@ public class SchemaBuilder {
/**
* A plain double type without custom properties. This is equivalent to:
- *
+ *
* <pre>
* doubleBuilder().endDouble();
* </pre>
@@ -1453,7 +1454,7 @@ public class SchemaBuilder {
/**
* A plain string type without custom properties. This is equivalent to:
- *
+ *
* <pre>
* stringBuilder().endString();
* </pre>
@@ -1472,7 +1473,7 @@ public class SchemaBuilder {
/**
* A plain bytes type without custom properties. This is equivalent to:
- *
+ *
* <pre>
* bytesBuilder().endBytes();
* </pre>
@@ -1491,7 +1492,7 @@ public class SchemaBuilder {
/**
* A plain null type without custom properties. This is equivalent to:
- *
+ *
* <pre>
* nullBuilder().endNull();
* </pre>
@@ -1560,11 +1561,11 @@ public class SchemaBuilder {
* value of the non-null type.
* <p/>
* For example, the two code snippets below are equivalent:
- *
+ *
* <pre>
* nullable().booleanType().booleanDefault(true)
* </pre>
- *
+ *
* <pre>
* unionOf().booleanType().and().nullType().endUnion().booleanDefault(true)
* </pre>
@@ -1577,11 +1578,11 @@ public class SchemaBuilder {
* A shortcut for building a union of null and a type, with a null default.
* <p/>
* For example, the two code snippets below are equivalent:
- *
+ *
* <pre>
* optional().booleanType()
* </pre>
- *
+ *
* <pre>
* unionOf().nullType().and().booleanType().endUnion().nullDefault()
* </pre>
@@ -1606,7 +1607,7 @@ public class SchemaBuilder {
/**
* A plain boolean type without custom properties. This is equivalent to:
- *
+ *
* <pre>
* booleanBuilder().endBoolean();
* </pre>
@@ -1625,7 +1626,7 @@ public class SchemaBuilder {
/**
* A plain int type without custom properties. This is equivalent to:
- *
+ *
* <pre>
* intBuilder().endInt();
* </pre>
@@ -1644,7 +1645,7 @@ public class SchemaBuilder {
/**
* A plain long type without custom properties. This is equivalent to:
- *
+ *
* <pre>
* longBuilder().endLong();
* </pre>
@@ -1663,7 +1664,7 @@ public class SchemaBuilder {
/**
* A plain float type without custom properties. This is equivalent to:
- *
+ *
* <pre>
* floatBuilder().endFloat();
* </pre>
@@ -1682,7 +1683,7 @@ public class SchemaBuilder {
/**
* A plain double type without custom properties. This is equivalent to:
- *
+ *
* <pre>
* doubleBuilder().endDouble();
* </pre>
@@ -1701,7 +1702,7 @@ public class SchemaBuilder {
/**
* A plain string type without custom properties. This is equivalent to:
- *
+ *
* <pre>
* stringBuilder().endString();
* </pre>
@@ -1720,7 +1721,7 @@ public class SchemaBuilder {
/**
* A plain bytes type without custom properties. This is equivalent to:
- *
+ *
* <pre>
* bytesBuilder().endBytes();
* </pre>
@@ -1739,7 +1740,7 @@ public class SchemaBuilder {
/**
* A plain null type without custom properties. This is equivalent to:
- *
+ *
* <pre>
* nullBuilder().endNull();
* </pre>
@@ -1822,7 +1823,7 @@ public class SchemaBuilder {
/**
* Add a field with the given name.
- *
+ *
* @return A {@link FieldBuilder} for the given name.
*/
public FieldBuilder<R> name(String fieldName) {
@@ -1833,7 +1834,7 @@ public class SchemaBuilder {
* Shortcut for creating a boolean field with the given name and no
default.
* <p/>
* This is equivalent to:
- *
+ *
* <pre>
* name(fieldName).type().booleanType().noDefault()
* </pre>
@@ -1847,7 +1848,7 @@ public class SchemaBuilder {
* with null default.
* <p/>
* This is equivalent to:
- *
+ *
* <pre>
* name(fieldName).type().optional().booleanType()
* </pre>
@@ -1874,7 +1875,7 @@ public class SchemaBuilder {
* Shortcut for creating an int field with the given name and no default.
* <p/>
* This is equivalent to:
- *
+ *
* <pre>
* name(fieldName).type().intType().noDefault()
* </pre>
@@ -1888,7 +1889,7 @@ public class SchemaBuilder {
* null default.
* <p/>
* This is equivalent to:
- *
+ *
* <pre>
* name(fieldName).type().optional().intType()
* </pre>
@@ -1902,7 +1903,7 @@ public class SchemaBuilder {
* int default.
* <p/>
* This is equivalent to:
- *
+ *
* <pre>
* name(fieldName).type().nullable().intType().intDefault(defaultVal)
* </pre>
@@ -1915,7 +1916,7 @@ public class SchemaBuilder {
* Shortcut for creating a long field with the given name and no default.
* <p/>
* This is equivalent to:
- *
+ *
* <pre>
* name(fieldName).type().longType().noDefault()
* </pre>
@@ -1929,7 +1930,7 @@ public class SchemaBuilder {
* null default.
* <p/>
* This is equivalent to:
- *
+ *
* <pre>
* name(fieldName).type().optional().longType()
* </pre>
@@ -1943,7 +1944,7 @@ public class SchemaBuilder {
* long default.
* <p/>
* This is equivalent to:
- *
+ *
* <pre>
* name(fieldName).type().nullable().longType().longDefault(defaultVal)
* </pre>
@@ -1956,7 +1957,7 @@ public class SchemaBuilder {
* Shortcut for creating a float field with the given name and no default.
* <p/>
* This is equivalent to:
- *
+ *
* <pre>
* name(fieldName).type().floatType().noDefault()
* </pre>
@@ -1970,7 +1971,7 @@ public class SchemaBuilder {
* null default.
* <p/>
* This is equivalent to:
- *
+ *
* <pre>
* name(fieldName).type().optional().floatType()
* </pre>
@@ -1984,7 +1985,7 @@ public class SchemaBuilder {
* a float default.
* <p/>
* This is equivalent to:
- *
+ *
* <pre>
* name(fieldName).type().nullable().floatType().floatDefault(defaultVal)
* </pre>
@@ -1997,7 +1998,7 @@ public class SchemaBuilder {
* Shortcut for creating a double field with the given name and no default.
* <p/>
* This is equivalent to:
- *
+ *
* <pre>
* name(fieldName).type().doubleType().noDefault()
* </pre>
@@ -2011,7 +2012,7 @@ public class SchemaBuilder {
* with null default.
* <p/>
* This is equivalent to:
- *
+ *
* <pre>
* name(fieldName).type().optional().doubleType()
* </pre>
@@ -2025,7 +2026,7 @@ public class SchemaBuilder {
* with a double default.
* <p/>
* This is equivalent to:
- *
+ *
* <pre>
* name(fieldName).type().nullable().doubleType().doubleDefault(defaultVal)
* </pre>
@@ -2038,7 +2039,7 @@ public class SchemaBuilder {
* Shortcut for creating a string field with the given name and no default.
* <p/>
* This is equivalent to:
- *
+ *
* <pre>
* name(fieldName).type().stringType().noDefault()
* </pre>
@@ -2052,7 +2053,7 @@ public class SchemaBuilder {
* with null default.
* <p/>
* This is equivalent to:
- *
+ *
* <pre>
* name(fieldName).type().optional().stringType()
* </pre>
@@ -2066,7 +2067,7 @@ public class SchemaBuilder {
* with a string default.
* <p/>
* This is equivalent to:
- *
+ *
* <pre>
* name(fieldName).type().nullable().stringType().stringDefault(defaultVal)
* </pre>
@@ -2079,7 +2080,7 @@ public class SchemaBuilder {
* Shortcut for creating a bytes field with the given name and no default.
* <p/>
* This is equivalent to:
- *
+ *
* <pre>
* name(fieldName).type().bytesType().noDefault()
* </pre>
@@ -2093,7 +2094,7 @@ public class SchemaBuilder {
* null default.
* <p/>
* This is equivalent to:
- *
+ *
* <pre>
* name(fieldName).type().optional().bytesType()
* </pre>
@@ -2107,7 +2108,7 @@ public class SchemaBuilder {
* a bytes default.
* <p/>
* This is equivalent to:
- *
+ *
* <pre>
* name(fieldName).type().nullable().bytesType().bytesDefault(defaultVal)
* </pre>
@@ -2137,11 +2138,11 @@ public class SchemaBuilder {
*
* Usage is to first configure any of the optional parameters and then to
call
* one of the type methods to complete the field. For example
- *
+ *
* <pre>
* .namespace("org.apache.example").orderDescending().type()
* </pre>
- *
+ *
* Optional parameters for a field are namespace, doc, order, and aliases.
*/
public final static class FieldBuilder<R> extends
NamedBuilder<FieldBuilder<R>> {
@@ -2174,7 +2175,7 @@ public class SchemaBuilder {
/**
* Final step in configuring this field, finalizing name, namespace,
alias, and
* order.
- *
+ *
* @return A builder for the field's type and default value.
*/
public FieldTypeBuilder<R> type() {
@@ -2225,16 +2226,16 @@ public class SchemaBuilder {
}
private FieldAssembler<R> completeField(Schema schema, Object defaultVal) {
- JsonNode defaultNode = toJsonNode(defaultVal);
+ JsonNode defaultNode = defaultVal == null ? NullNode.getInstance() :
toJsonNode(defaultVal);
return completeField(schema, defaultNode);
}
private FieldAssembler<R> completeField(Schema schema) {
- return completeField(schema, null);
+ return completeField(schema, (JsonNode) null);
}
private FieldAssembler<R> completeField(Schema schema, JsonNode
defaultVal) {
- Field field = new Field(name(), schema, doc(), defaultVal, order);
+ Field field = new Field(name(), schema, doc(), defaultVal, true, order);
addPropsTo(field);
addAliasesTo(field);
return fields.addField(field);
diff --git
a/lang/java/avro/src/test/java/org/apache/avro/TestCircularReferences.java
b/lang/java/avro/src/test/java/org/apache/avro/TestCircularReferences.java
index e5ef87a..dbf5d39 100644
--- a/lang/java/avro/src/test/java/org/apache/avro/TestCircularReferences.java
+++ b/lang/java/avro/src/test/java/org/apache/avro/TestCircularReferences.java
@@ -289,14 +289,14 @@ public class TestCircularReferences {
Reference parentRef = new Reference("parent");
List<Schema.Field> childFields = new ArrayList<>();
- childFields.add(new Schema.Field("c", Schema.create(Schema.Type.STRING),
null, null));
- childFields.add(new Schema.Field("parent", parentRefSchema, null, null));
+ childFields.add(new Schema.Field("c", Schema.create(Schema.Type.STRING)));
+ childFields.add(new Schema.Field("parent", parentRefSchema));
Schema childSchema = parentRef.addToSchema(Schema.createRecord("Child",
null, null, false, childFields));
List<Schema.Field> parentFields = new ArrayList<>();
- parentFields.add(new Schema.Field("id", Schema.create(Schema.Type.LONG),
null, null));
- parentFields.add(new Schema.Field("p", Schema.create(Schema.Type.STRING),
null, null));
- parentFields.add(new Schema.Field("child", childSchema, null, null));
+ parentFields.add(new Schema.Field("id", Schema.create(Schema.Type.LONG)));
+ parentFields.add(new Schema.Field("p", Schema.create(Schema.Type.STRING)));
+ parentFields.add(new Schema.Field("child", childSchema));
parentSchema.setFields(parentFields);
Referenceable idRef = new Referenceable("id");
diff --git
a/lang/java/avro/src/test/java/org/apache/avro/TestSchemaBuilder.java
b/lang/java/avro/src/test/java/org/apache/avro/TestSchemaBuilder.java
index a969466..f440087 100644
--- a/lang/java/avro/src/test/java/org/apache/avro/TestSchemaBuilder.java
+++ b/lang/java/avro/src/test/java/org/apache/avro/TestSchemaBuilder.java
@@ -44,23 +44,32 @@ public class TestSchemaBuilder {
public void testRecord() {
Schema schema =
SchemaBuilder.record("myrecord").namespace("org.example").aliases("oldrecord").fields().name("f0")
.aliases("f0alias").type().stringType().noDefault().name("f1").doc("This is
f1").type().longType().noDefault()
-
.name("f2").type().nullable().booleanType().booleanDefault(true).endRecord();
+
.name("f2").type().nullable().booleanType().booleanDefault(true).name("f3").type().unionOf().nullType().and()
+ .booleanType().endUnion().nullDefault().endRecord();
Assert.assertEquals("myrecord", schema.getName());
Assert.assertEquals("org.example", schema.getNamespace());
Assert.assertEquals("org.example.oldrecord",
schema.getAliases().iterator().next());
Assert.assertFalse(schema.isError());
List<Schema.Field> fields = schema.getFields();
- Assert.assertEquals(3, fields.size());
- Assert.assertEquals(new Schema.Field("f0",
Schema.create(Schema.Type.STRING), null, null), fields.get(0));
+ Assert.assertEquals(4, fields.size());
+ Assert.assertEquals(new Schema.Field("f0",
Schema.create(Schema.Type.STRING)), fields.get(0));
Assert.assertTrue(fields.get(0).aliases().contains("f0alias"));
- Assert.assertEquals(new Schema.Field("f1",
Schema.create(Schema.Type.LONG), "This is f1", null), fields.get(1));
+ Assert.assertEquals(new Schema.Field("f1",
Schema.create(Schema.Type.LONG), "This is f1"), fields.get(1));
List<Schema> types = new ArrayList<>();
types.add(Schema.create(Schema.Type.BOOLEAN));
types.add(Schema.create(Schema.Type.NULL));
Schema optional = Schema.createUnion(types);
Assert.assertEquals(new Schema.Field("f2", optional, null, true),
fields.get(2));
+
+ List<Schema> types2 = new ArrayList<>();
+ types2.add(Schema.create(Schema.Type.NULL));
+ types2.add(Schema.create(Schema.Type.BOOLEAN));
+ Schema optional2 = Schema.createUnion(types2);
+
+ Assert.assertNotEquals(new Schema.Field("f3", optional2, null, (Object)
null), fields.get(3));
+ Assert.assertEquals(new Schema.Field("f3", optional2, null,
Schema.Field.NULL_DEFAULT_VALUE), fields.get(3));
}
@Test
@@ -426,7 +435,7 @@ public class TestSchemaBuilder {
Assert.assertEquals("LongList", schema.getName());
List<Schema.Field> fields = schema.getFields();
Assert.assertEquals(2, fields.size());
- Assert.assertEquals(new Schema.Field("value",
Schema.create(Schema.Type.LONG), null, null), fields.get(0));
+ Assert.assertEquals(new Schema.Field("value",
Schema.create(Schema.Type.LONG), null), fields.get(0));
Assert.assertEquals(Schema.Type.UNION, fields.get(1).schema().getType());
diff --git
a/lang/java/avro/src/test/java/org/apache/avro/file/TestSeekableByteArrayInput.java
b/lang/java/avro/src/test/java/org/apache/avro/file/TestSeekableByteArrayInput.java
index 327d66d..8ec113c 100644
---
a/lang/java/avro/src/test/java/org/apache/avro/file/TestSeekableByteArrayInput.java
+++
b/lang/java/avro/src/test/java/org/apache/avro/file/TestSeekableByteArrayInput.java
@@ -47,7 +47,7 @@ public class TestSeekableByteArrayInput {
private Schema getTestSchema() throws Exception {
Schema schema = Schema.createRecord("TestRecord", "this is a test record",
"org.apache.avro.file", false);
List<Field> fields = new ArrayList<>();
- fields.add(new Field("name", Schema.create(Type.STRING), "this is a test
field", null));
+ fields.add(new Field("name", Schema.create(Type.STRING), "this is a test
field"));
schema.setFields(fields);
return schema;
}