blob: 2679c5d571e075d74e741c69eaad8a9ceba724bc [file] [log] [blame]
/*
* 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
*
* https://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 java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.*;
import com.fasterxml.jackson.databind.node.NullNode;
import org.apache.avro.Schema.Field.Order;
import org.apache.avro.file.DataFileReader;
import org.apache.avro.file.DataFileWriter;
import org.apache.avro.generic.GenericData;
import org.apache.avro.generic.GenericDatumReader;
import org.apache.avro.generic.GenericDatumWriter;
import org.apache.avro.generic.GenericRecordBuilder;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
public class TestSchemaBuilder {
@Rule
public TemporaryFolder DIR = new TemporaryFolder();
@Test
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).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(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"), 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
public void testDoc() {
Schema s = SchemaBuilder.fixed("myfixed").doc("mydoc").size(1);
Assert.assertEquals("mydoc", s.getDoc());
}
@Test
public void testProps() {
Schema s = SchemaBuilder.builder().intBuilder().prop("p1", "v1").prop("p2", "v2").prop("p2", "v2real") // overwrite
.endInt();
int size = s.getObjectProps().size();
Assert.assertEquals(2, size);
Assert.assertEquals("v1", s.getProp("p1"));
Assert.assertEquals("v2real", s.getProp("p2"));
}
@Test
public void testObjectProps() {
Schema s = SchemaBuilder.builder().intBuilder().prop("booleanProp", true).prop("intProp", Integer.MAX_VALUE)
.prop("longProp", Long.MAX_VALUE).prop("floatProp", 1.0f).prop("doubleProp", Double.MAX_VALUE)
.prop("byteProp", new byte[] { 0x41, 0x42, 0x43 }).prop("stringProp", "abc").endInt();
// object properties
Assert.assertEquals(7, s.getObjectProps().size());
Assert.assertTrue(s.getObjectProp("booleanProp") instanceof Boolean);
Assert.assertEquals(true, s.getObjectProp("booleanProp"));
Assert.assertTrue(s.getObjectProp("intProp") instanceof Integer);
Assert.assertEquals(Integer.MAX_VALUE, s.getObjectProp("intProp"));
Assert.assertTrue(s.getObjectProp("intProp") instanceof Integer);
Assert.assertTrue(s.getObjectProp("longProp") instanceof Long);
Assert.assertEquals(Long.MAX_VALUE, s.getObjectProp("longProp"));
Assert.assertTrue(s.getObjectProp("floatProp") instanceof Double);
// float converts to double
Assert.assertEquals(1.0d, s.getObjectProp("floatProp"));
Assert.assertTrue(s.getObjectProp("doubleProp") instanceof Double);
Assert.assertEquals(Double.MAX_VALUE, s.getObjectProp("doubleProp"));
// byte[] converts to string
Assert.assertTrue(s.getObjectProp("byteProp") instanceof String);
Assert.assertEquals("ABC", s.getObjectProp("byteProp"));
Assert.assertTrue(s.getObjectProp("stringProp") instanceof String);
Assert.assertEquals("abc", s.getObjectProp("stringProp"));
}
@Test
public void testFieldObjectProps() {
Schema s = SchemaBuilder.builder().record("MyRecord").fields().name("myField").prop("booleanProp", true)
.prop("intProp", Integer.MAX_VALUE).prop("longProp", Long.MAX_VALUE).prop("floatProp", 1.0f)
.prop("doubleProp", Double.MAX_VALUE).prop("byteProp", new byte[] { 0x41, 0x42, 0x43 })
.prop("stringProp", "abc").type().intType().noDefault().endRecord();
Schema.Field f = s.getField("myField");
// object properties
Assert.assertEquals(7, f.getObjectProps().size());
Assert.assertTrue(f.getObjectProp("booleanProp") instanceof Boolean);
Assert.assertEquals(true, f.getObjectProp("booleanProp"));
Assert.assertTrue(f.getObjectProp("intProp") instanceof Integer);
Assert.assertEquals(Integer.MAX_VALUE, f.getObjectProp("intProp"));
Assert.assertTrue(f.getObjectProp("intProp") instanceof Integer);
Assert.assertTrue(f.getObjectProp("longProp") instanceof Long);
Assert.assertEquals(Long.MAX_VALUE, f.getObjectProp("longProp"));
Assert.assertTrue(f.getObjectProp("floatProp") instanceof Double);
// float converts to double
Assert.assertEquals(1.0d, f.getObjectProp("floatProp"));
Assert.assertTrue(f.getObjectProp("doubleProp") instanceof Double);
Assert.assertEquals(Double.MAX_VALUE, f.getObjectProp("doubleProp"));
// byte[] converts to string
Assert.assertTrue(f.getObjectProp("byteProp") instanceof String);
Assert.assertEquals("ABC", f.getObjectProp("byteProp"));
Assert.assertTrue(f.getObjectProp("stringProp") instanceof String);
Assert.assertEquals("abc", f.getObjectProp("stringProp"));
}
@Test
public void testArrayObjectProp() {
List<Object> values = new ArrayList<>();
values.add(true);
values.add(Integer.MAX_VALUE);
values.add(Long.MAX_VALUE);
values.add(1.0f);
values.add(Double.MAX_VALUE);
values.add(new byte[] { 0x41, 0x42, 0x43 });
values.add("abc");
Schema s = SchemaBuilder.builder().intBuilder().prop("arrayProp", values).endInt();
// object properties
Assert.assertEquals(1, s.getObjectProps().size());
Assert.assertTrue(s.getObjectProp("arrayProp") instanceof Collection);
@SuppressWarnings("unchecked")
Collection<Object> valueCollection = (Collection<Object>) s.getObjectProp("arrayProp");
Iterator<Object> iter = valueCollection.iterator();
Assert.assertEquals(7, valueCollection.size());
Assert.assertEquals(true, iter.next());
Assert.assertEquals(Integer.MAX_VALUE, iter.next());
Assert.assertEquals(Long.MAX_VALUE, iter.next());
// float converts to double
Assert.assertEquals(1.0d, iter.next());
Assert.assertEquals(Double.MAX_VALUE, iter.next());
// byte[] converts to string
Assert.assertEquals("ABC", iter.next());
Assert.assertEquals("abc", iter.next());
}
@Test
public void testFieldArrayObjectProp() {
List<Object> values = new ArrayList<>();
values.add(true);
values.add(Integer.MAX_VALUE);
values.add(Long.MAX_VALUE);
values.add(1.0f);
values.add(Double.MAX_VALUE);
values.add(new byte[] { 0x41, 0x42, 0x43 });
values.add("abc");
Schema s = SchemaBuilder.builder().record("MyRecord").fields().name("myField").prop("arrayProp", values).type()
.intType().noDefault().endRecord();
Schema.Field f = s.getField("myField");
// object properties
Assert.assertEquals(1, f.getObjectProps().size());
Assert.assertTrue(f.getObjectProp("arrayProp") instanceof Collection);
@SuppressWarnings("unchecked")
Collection<Object> valueCollection = (Collection<Object>) f.getObjectProp("arrayProp");
Iterator<Object> iter = valueCollection.iterator();
Assert.assertEquals(7, valueCollection.size());
Assert.assertEquals(true, iter.next());
Assert.assertEquals(Integer.MAX_VALUE, iter.next());
Assert.assertEquals(Long.MAX_VALUE, iter.next());
// float converts to double
Assert.assertEquals(1.0d, iter.next());
Assert.assertEquals(Double.MAX_VALUE, iter.next());
// byte[] converts to string
Assert.assertEquals("ABC", iter.next());
Assert.assertEquals("abc", iter.next());
}
@Test
public void testMapObjectProp() {
Map<String, Object> values = new HashMap<>();
values.put("booleanKey", true);
values.put("intKey", Integer.MAX_VALUE);
values.put("longKey", Long.MAX_VALUE);
values.put("floatKey", 1.0f);
values.put("doubleKey", Double.MAX_VALUE);
values.put("byteKey", new byte[] { 0x41, 0x42, 0x43 });
values.put("stringKey", "abc");
Schema s = SchemaBuilder.builder().intBuilder().prop("mapProp", values).endInt();
// object properties
Assert.assertTrue(s.getObjectProp("mapProp") instanceof Map);
@SuppressWarnings("unchecked")
Map<String, Object> valueMap = (Map<String, Object>) s.getObjectProp("mapProp");
Assert.assertEquals(values.size(), valueMap.size());
Assert.assertTrue(valueMap.get("booleanKey") instanceof Boolean);
Assert.assertEquals(true, valueMap.get("booleanKey"));
Assert.assertTrue(valueMap.get("intKey") instanceof Integer);
Assert.assertEquals(Integer.MAX_VALUE, valueMap.get("intKey"));
Assert.assertTrue(valueMap.get("longKey") instanceof Long);
Assert.assertEquals(Long.MAX_VALUE, valueMap.get("longKey"));
// float converts to double
Assert.assertTrue(valueMap.get("floatKey") instanceof Double);
Assert.assertEquals(1.0d, valueMap.get("floatKey"));
Assert.assertTrue(valueMap.get("doubleKey") instanceof Double);
Assert.assertEquals(Double.MAX_VALUE, valueMap.get("doubleKey"));
// byte[] converts to string
Assert.assertTrue(valueMap.get("byteKey") instanceof String);
Assert.assertEquals("ABC", valueMap.get("byteKey"));
Assert.assertTrue(valueMap.get("stringKey") instanceof String);
Assert.assertEquals("abc", valueMap.get("stringKey"));
}
@Test
public void testFieldMapObjectProp() {
Map<String, Object> values = new HashMap<>();
values.put("booleanKey", true);
values.put("intKey", Integer.MAX_VALUE);
values.put("longKey", Long.MAX_VALUE);
values.put("floatKey", 1.0f);
values.put("doubleKey", Double.MAX_VALUE);
values.put("byteKey", new byte[] { 0x41, 0x42, 0x43 });
values.put("stringKey", "abc");
Schema s = SchemaBuilder.builder().record("MyRecord").fields().name("myField").prop("mapProp", values).type()
.intType().noDefault().endRecord();
Schema.Field f = s.getField("myField");
// object properties
Assert.assertTrue(f.getObjectProp("mapProp") instanceof Map);
@SuppressWarnings("unchecked")
Map<String, Object> valueMap = (Map<String, Object>) f.getObjectProp("mapProp");
Assert.assertEquals(values.size(), valueMap.size());
Assert.assertTrue(valueMap.get("booleanKey") instanceof Boolean);
Assert.assertEquals(true, valueMap.get("booleanKey"));
Assert.assertTrue(valueMap.get("intKey") instanceof Integer);
Assert.assertEquals(Integer.MAX_VALUE, valueMap.get("intKey"));
Assert.assertTrue(valueMap.get("longKey") instanceof Long);
Assert.assertEquals(Long.MAX_VALUE, valueMap.get("longKey"));
// float converts to double
Assert.assertTrue(valueMap.get("floatKey") instanceof Double);
Assert.assertEquals(1.0d, valueMap.get("floatKey"));
Assert.assertTrue(valueMap.get("doubleKey") instanceof Double);
Assert.assertEquals(Double.MAX_VALUE, valueMap.get("doubleKey"));
// byte[] converts to string
Assert.assertTrue(valueMap.get("byteKey") instanceof String);
Assert.assertEquals("ABC", valueMap.get("byteKey"));
Assert.assertTrue(valueMap.get("stringKey") instanceof String);
Assert.assertEquals("abc", valueMap.get("stringKey"));
}
@Test(expected = AvroRuntimeException.class)
public void testNullObjectProp() {
SchemaBuilder.builder().intBuilder().prop("nullProp", (Object) null).endInt();
}
@Test(expected = AvroRuntimeException.class)
public void testFieldNullObjectProp() {
SchemaBuilder.builder().record("MyRecord").fields().name("myField").prop("nullProp", (Object) null).type().intType()
.noDefault().endRecord();
}
@Test
public void testNamespaces() {
Schema s1 = SchemaBuilder.record("myrecord").namespace("org.example").fields().name("myint").type().intType()
.noDefault().endRecord();
Schema s2 = SchemaBuilder.record("org.example.myrecord").fields().name("myint").type().intType().noDefault()
.endRecord();
Schema s3 = SchemaBuilder.record("org.example.myrecord").namespace("org.example2").fields().name("myint").type()
.intType().noDefault().endRecord();
Schema s4 = SchemaBuilder.builder("org.example").record("myrecord").fields().name("myint").type().intType()
.noDefault().endRecord();
Assert.assertEquals("myrecord", s1.getName());
Assert.assertEquals("myrecord", s2.getName());
Assert.assertEquals("myrecord", s3.getName());
Assert.assertEquals("myrecord", s4.getName());
Assert.assertEquals("org.example", s1.getNamespace());
Assert.assertEquals("org.example", s2.getNamespace());
Assert.assertEquals("org.example", s3.getNamespace()); // namespace call is ignored
Assert.assertEquals("org.example", s4.getNamespace());
Assert.assertEquals("org.example.myrecord", s1.getFullName());
Assert.assertEquals("org.example.myrecord", s2.getFullName());
Assert.assertEquals("org.example.myrecord", s3.getFullName());
Assert.assertEquals("org.example.myrecord", s4.getFullName());
}
@Test(expected = NullPointerException.class)
public void testMissingRecordName() {
SchemaBuilder.record(null).fields() // null name
.name("f0").type().stringType().noDefault().endRecord();
}
@Test
public void testBoolean() {
Schema.Type type = Schema.Type.BOOLEAN;
Schema simple = SchemaBuilder.builder().booleanType();
Schema expected = primitive(type, simple);
Schema built1 = SchemaBuilder.builder().booleanBuilder().prop("p", "v").endBoolean();
Assert.assertEquals(expected, built1);
}
@Test
public void testInt() {
Schema.Type type = Schema.Type.INT;
Schema simple = SchemaBuilder.builder().intType();
Schema expected = primitive(type, simple);
Schema built1 = SchemaBuilder.builder().intBuilder().prop("p", "v").endInt();
Assert.assertEquals(expected, built1);
}
@Test
public void testLong() {
Schema.Type type = Schema.Type.LONG;
Schema simple = SchemaBuilder.builder().longType();
Schema expected = primitive(type, simple);
Schema built1 = SchemaBuilder.builder().longBuilder().prop("p", "v").endLong();
Assert.assertEquals(expected, built1);
}
@Test
public void testFloat() {
Schema.Type type = Schema.Type.FLOAT;
Schema simple = SchemaBuilder.builder().floatType();
Schema expected = primitive(type, simple);
Schema built1 = SchemaBuilder.builder().floatBuilder().prop("p", "v").endFloat();
Assert.assertEquals(expected, built1);
}
@Test
public void testDuble() {
Schema.Type type = Schema.Type.DOUBLE;
Schema simple = SchemaBuilder.builder().doubleType();
Schema expected = primitive(type, simple);
Schema built1 = SchemaBuilder.builder().doubleBuilder().prop("p", "v").endDouble();
Assert.assertEquals(expected, built1);
}
@Test
public void testString() {
Schema.Type type = Schema.Type.STRING;
Schema simple = SchemaBuilder.builder().stringType();
Schema expected = primitive(type, simple);
Schema built1 = SchemaBuilder.builder().stringBuilder().prop("p", "v").endString();
Assert.assertEquals(expected, built1);
}
@Test
public void testBytes() {
Schema.Type type = Schema.Type.BYTES;
Schema simple = SchemaBuilder.builder().bytesType();
Schema expected = primitive(type, simple);
Schema built1 = SchemaBuilder.builder().bytesBuilder().prop("p", "v").endBytes();
Assert.assertEquals(expected, built1);
}
@Test
public void testNull() {
Schema.Type type = Schema.Type.NULL;
Schema simple = SchemaBuilder.builder().nullType();
Schema expected = primitive(type, simple);
Schema built1 = SchemaBuilder.builder().nullBuilder().prop("p", "v").endNull();
Assert.assertEquals(expected, built1);
}
private Schema primitive(Schema.Type type, Schema bare) {
// test creation of bare schema by name
Schema bareByName = SchemaBuilder.builder().type(type.getName());
Assert.assertEquals(Schema.create(type), bareByName);
Assert.assertEquals(bareByName, bare);
// return a schema with custom prop set
Schema p = Schema.create(type);
p.addProp("p", "v");
return p;
}
// @Test
// public void testError() {
// Schema schema = SchemaBuilder
// .errorType("myerror")
// .requiredString("message")
// .build();
//
// Assert.assertEquals("myerror", schema.getName());
// Assert.assertTrue(schema.isError());
// }
@Test
public void testRecursiveRecord() {
Schema schema = SchemaBuilder.record("LongList").fields().name("value").type().longType().noDefault().name("next")
.type().optional().type("LongList").endRecord();
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), fields.get(0));
Assert.assertEquals(Schema.Type.UNION, fields.get(1).schema().getType());
Assert.assertEquals(Schema.Type.NULL, fields.get(1).schema().getTypes().get(0).getType());
Schema recordSchema = fields.get(1).schema().getTypes().get(1);
Assert.assertEquals(Schema.Type.RECORD, recordSchema.getType());
Assert.assertEquals("LongList", recordSchema.getName());
Assert.assertEquals(NullNode.getInstance(), fields.get(1).defaultValue());
}
@Test
public void testEnum() {
List<String> symbols = Arrays.asList("a", "b");
Schema expected = Schema.createEnum("myenum", null, null, symbols);
expected.addProp("p", "v");
Schema schema = SchemaBuilder.enumeration("myenum").prop("p", "v").symbols("a", "b");
Assert.assertEquals(expected, schema);
}
@Test
public void testEnumWithDefault() {
List<String> symbols = Arrays.asList("a", "b");
String enumDefault = "a";
Schema expected = Schema.createEnum("myenum", null, null, symbols, enumDefault);
expected.addProp("p", "v");
Schema schema = SchemaBuilder.enumeration("myenum").prop("p", "v").defaultSymbol(enumDefault).symbols("a", "b");
Assert.assertEquals(expected, schema);
}
@Test
public void testFixed() {
Schema expected = Schema.createFixed("myfixed", null, null, 16);
expected.addAlias("myOldFixed");
Schema schema = SchemaBuilder.fixed("myfixed").aliases("myOldFixed").size(16);
Assert.assertEquals(expected, schema);
}
@Test
public void testArray() {
Schema longSchema = Schema.create(Schema.Type.LONG);
Schema expected = Schema.createArray(longSchema);
Schema schema1 = SchemaBuilder.array().items().longType();
Assert.assertEquals(expected, schema1);
Schema schema2 = SchemaBuilder.array().items(longSchema);
Assert.assertEquals(expected, schema2);
Schema schema3 = SchemaBuilder.array().prop("p", "v").items().type("long");
expected.addProp("p", "v");
Assert.assertEquals(expected, schema3);
}
@Test
public void testMap() {
Schema intSchema = Schema.create(Schema.Type.INT);
Schema expected = Schema.createMap(intSchema);
Schema schema1 = SchemaBuilder.map().values().intType();
Assert.assertEquals(expected, schema1);
Schema schema2 = SchemaBuilder.map().values(intSchema);
Assert.assertEquals(expected, schema2);
Schema schema3 = SchemaBuilder.map().prop("p", "v").values().type("int");
expected.addProp("p", "v");
Assert.assertEquals(expected, schema3);
}
@Test
public void testUnionAndNullable() {
List<Schema> types = new ArrayList<>();
types.add(Schema.create(Schema.Type.LONG));
types.add(Schema.create(Schema.Type.NULL));
Schema expected = Schema.createUnion(types);
Schema schema = SchemaBuilder.unionOf().longType().and().nullType().endUnion();
Assert.assertEquals(expected, schema);
schema = SchemaBuilder.nullable().longType();
Assert.assertEquals(expected, schema);
}
@Test
public void testFields() {
Schema rec = SchemaBuilder.record("Rec").fields().name("documented").doc("documented").type().nullType().noDefault()
.name("ascending").orderAscending().type().booleanType().noDefault().name("descending").orderDescending().type()
.floatType().noDefault().name("ignored").orderIgnore().type().doubleType().noDefault().name("aliased")
.aliases("anAlias").type().stringType().noDefault().endRecord();
Assert.assertEquals("documented", rec.getField("documented").doc());
Assert.assertEquals(Order.ASCENDING, rec.getField("ascending").order());
Assert.assertEquals(Order.DESCENDING, rec.getField("descending").order());
Assert.assertEquals(Order.IGNORE, rec.getField("ignored").order());
Assert.assertTrue(rec.getField("aliased").aliases().contains("anAlias"));
}
@Test
public void testFieldShortcuts() {
Schema full = SchemaBuilder.record("Blah").fields().name("rbool").type().booleanType().noDefault().name("obool")
.type().optional().booleanType().name("nbool").type().nullable().booleanType().booleanDefault(true).name("rint")
.type().intType().noDefault().name("oint").type().optional().intType().name("nint").type().nullable().intType()
.intDefault(1).name("rlong").type().longType().noDefault().name("olong").type().optional().longType()
.name("nlong").type().nullable().longType().longDefault(2L).name("rfloat").type().floatType().noDefault()
.name("ofloat").type().optional().floatType().name("nfloat").type().nullable().floatType().floatDefault(-1.1f)
.name("rdouble").type().doubleType().noDefault().name("odouble").type().optional().doubleType().name("ndouble")
.type().nullable().doubleType().doubleDefault(99.9d).name("rstring").type().stringType().noDefault()
.name("ostring").type().optional().stringType().name("nstring").type().nullable().stringType()
.stringDefault("def").name("rbytes").type().bytesType().noDefault().name("obytes").type().optional().bytesType()
.name("nbytes").type().nullable().bytesType().bytesDefault(new byte[] { 1, 2, 3 }).endRecord();
Schema shortcut = SchemaBuilder.record("Blah").fields().requiredBoolean("rbool").optionalBoolean("obool")
.nullableBoolean("nbool", true).requiredInt("rint").optionalInt("oint").nullableInt("nint", 1)
.requiredLong("rlong").optionalLong("olong").nullableLong("nlong", 2L).requiredFloat("rfloat")
.optionalFloat("ofloat").nullableFloat("nfloat", -1.1f).requiredDouble("rdouble").optionalDouble("odouble")
.nullableDouble("ndouble", 99.9d).requiredString("rstring").optionalString("ostring")
.nullableString("nstring", "def").requiredBytes("rbytes").optionalBytes("obytes")
.nullableBytes("nbytes", new byte[] { 1, 2, 3 }).endRecord();
Assert.assertEquals(full, shortcut);
}
@Test
public void testNames() {
// no contextual namespace
Schema r = SchemaBuilder.record("Rec").fields().name("f0").type().fixed("org.foo.MyFixed").size(1).noDefault()
.name("f1").type("org.foo.MyFixed").noDefault().name("f2").type("org.foo.MyFixed", "").noDefault().name("f3")
.type("org.foo.MyFixed", null).noDefault().name("f4").type("org.foo.MyFixed", "ignorethis").noDefault()
.name("f5").type("MyFixed", "org.foo").noDefault().endRecord();
Schema expected = Schema.createFixed("org.foo.MyFixed", null, null, 1);
checkField(r, expected, "f0");
checkField(r, expected, "f1");
checkField(r, expected, "f2");
checkField(r, expected, "f3");
checkField(r, expected, "f4");
checkField(r, expected, "f5");
// context namespace
Schema f = SchemaBuilder.builder("").fixed("Foo").size(1);
Assert.assertEquals(Schema.createFixed("Foo", null, null, 1), f);
// context namespace from record matches
r = SchemaBuilder.record("Rec").namespace("org.foo").fields().name("f0").type().fixed("MyFixed").size(1).noDefault()
.name("f1").type("org.foo.MyFixed").noDefault().name("f2").type("org.foo.MyFixed", "").noDefault().name("f3")
.type("org.foo.MyFixed", null).noDefault().name("f4").type("org.foo.MyFixed", "ignorethis").noDefault()
.name("f5").type("MyFixed", "org.foo").noDefault().name("f6").type("MyFixed", null).noDefault().name("f7")
.type("MyFixed").noDefault().endRecord();
checkField(r, expected, "f0");
checkField(r, expected, "f1");
checkField(r, expected, "f2");
checkField(r, expected, "f3");
checkField(r, expected, "f4");
checkField(r, expected, "f5");
checkField(r, expected, "f6");
checkField(r, expected, "f7");
// context namespace from record does not match
r = SchemaBuilder.record("Rec").namespace("org.rec").fields().name("f0").type().fixed("MyFixed")
.namespace("org.foo").size(1).noDefault().name("f1").type("org.foo.MyFixed").noDefault().name("f2")
.type("org.foo.MyFixed", "").noDefault().name("f3").type("org.foo.MyFixed", null).noDefault().name("f4")
.type("org.foo.MyFixed", "ignorethis").noDefault().name("f5").type("MyFixed", "org.foo").noDefault()
.endRecord();
checkField(r, expected, "f0");
checkField(r, expected, "f1");
checkField(r, expected, "f2");
checkField(r, expected, "f3");
checkField(r, expected, "f4");
checkField(r, expected, "f5");
// context namespace from record, nested has no namespace
expected = Schema.createFixed("MyFixed", null, null, 1);
r = SchemaBuilder.record("Rec").namespace("org.rec").fields().name("f0").type().fixed("MyFixed").namespace("")
.size(1).noDefault().name("f1").type("MyFixed", "").noDefault().endRecord();
checkField(r, expected, "f0");
checkField(r, expected, "f1");
// mimic names of primitives, but with a namesapce. This is OK
SchemaBuilder.fixed("org.test.long").size(1);
SchemaBuilder.fixed("long").namespace("org.test").size(1);
SchemaBuilder.builder("org.test").fixed("long").size(1);
}
private void checkField(Schema r, Schema expected, String name) {
Assert.assertEquals(expected, r.getField(name).schema());
}
@Test(expected = SchemaParseException.class)
public void testNamesFailRedefined() {
SchemaBuilder.record("Rec").fields().name("f0").type().enumeration("MyEnum").symbols("A", "B").enumDefault("A")
.name("f1").type().enumeration("MyEnum").symbols("X", "Y").noDefault().endRecord();
}
@Test(expected = SchemaParseException.class)
public void testNamesFailAbsent() {
SchemaBuilder.builder().type("notdefined");
}
@Test(expected = AvroTypeException.class)
public void testNameReserved() {
SchemaBuilder.fixed("long").namespace("").size(1);
}
@Test
public void testFieldTypesAndDefaultValues() {
byte[] bytedef = new byte[] { 3 };
ByteBuffer bufdef = ByteBuffer.wrap(bytedef);
String strdef = "\u0003";
HashMap<String, String> mapdef = new HashMap<>();
mapdef.put("a", "A");
ArrayList<String> arrdef = new ArrayList<>();
arrdef.add("arr");
Schema rec = SchemaBuilder.record("inner").fields().name("f").type().intType().noDefault().endRecord();
Schema rec2 = SchemaBuilder.record("inner2").fields().name("f2").type().intType().noDefault().endRecord();
GenericData.Record recdef = new GenericRecordBuilder(rec).set("f", 1).build();
GenericData.Record recdef2 = new GenericRecordBuilder(rec2).set("f2", 2).build();
Schema r = SchemaBuilder.record("r").fields().name("boolF").type().booleanType().booleanDefault(false).name("intF")
.type().intType().intDefault(1).name("longF").type().longType().longDefault(2L).name("floatF").type()
.floatType().floatDefault(3.0f).name("doubleF").type().doubleType().doubleDefault(4.0d).name("stringF").type()
.stringType().stringDefault("def").name("bytesF1").type().bytesType().bytesDefault(bytedef).name("bytesF2")
.type().bytesType().bytesDefault(bufdef).name("bytesF3").type().bytesType().bytesDefault(strdef).name("nullF")
.type().nullType().nullDefault().name("fixedF1").type().fixed("F1").size(1).fixedDefault(bytedef)
.name("fixedF2").type().fixed("F2").size(1).fixedDefault(bufdef).name("fixedF3").type().fixed("F3").size(1)
.fixedDefault(strdef).name("enumF").type().enumeration("E1").symbols("S").enumDefault("S").name("mapF").type()
.map().values().stringType().mapDefault(mapdef).name("arrayF").type().array().items().stringType()
.arrayDefault(arrdef).name("recordF").type().record("inner").fields().name("f").type().intType().noDefault()
.endRecord().recordDefault(recdef).name("byName").type("E1").withDefault("S")
// union builders, one for each 'first type' in a union:
.name("boolU").type().unionOf().booleanType().and().intType().endUnion().booleanDefault(false).name("intU")
.type().unionOf().intType().and().longType().endUnion().intDefault(1).name("longU").type().unionOf().longType()
.and().intType().endUnion().longDefault(2L).name("floatU").type().unionOf().floatType().and().intType()
.endUnion().floatDefault(3.0f).name("doubleU").type().unionOf().doubleType().and().intType().endUnion()
.doubleDefault(4.0d).name("stringU").type().unionOf().stringType().and().intType().endUnion()
.stringDefault("def").name("bytesU").type().unionOf().bytesType().and().intType().endUnion()
.bytesDefault(bytedef).name("nullU").type().unionOf().nullType().and().intType().endUnion().nullDefault()
.name("fixedU").type().unionOf().fixed("F4").size(1).and().intType().endUnion().fixedDefault(bytedef)
.name("enumU").type().unionOf().enumeration("E2").symbols("SS").and().intType().endUnion().enumDefault("SS")
.name("mapU").type().unionOf().map().values().stringType().and().intType().endUnion().mapDefault(mapdef)
.name("arrayU").type().unionOf().array().items().stringType().and().intType().endUnion().arrayDefault(arrdef)
.name("recordU").type().unionOf().record("inner2").fields().name("f2").type().intType().noDefault().endRecord()
.and().intType().endUnion().recordDefault(recdef2).endRecord();
GenericData.Record newRec = new GenericRecordBuilder(r).build();
Assert.assertEquals(false, newRec.get("boolF"));
Assert.assertEquals(false, newRec.get("boolU"));
Assert.assertEquals(1, newRec.get("intF"));
Assert.assertEquals(1, newRec.get("intU"));
Assert.assertEquals(2L, newRec.get("longF"));
Assert.assertEquals(2L, newRec.get("longU"));
Assert.assertEquals(3f, newRec.get("floatF"));
Assert.assertEquals(3f, newRec.get("floatU"));
Assert.assertEquals(4d, newRec.get("doubleF"));
Assert.assertEquals(4d, newRec.get("doubleU"));
Assert.assertEquals("def", newRec.get("stringF").toString());
Assert.assertEquals("def", newRec.get("stringU").toString());
Assert.assertEquals(bufdef, newRec.get("bytesF1"));
Assert.assertEquals(bufdef, newRec.get("bytesF2"));
Assert.assertEquals(bufdef, newRec.get("bytesF3"));
Assert.assertEquals(bufdef, newRec.get("bytesU"));
Assert.assertNull(newRec.get("nullF"));
Assert.assertNull(newRec.get("nullU"));
Assert.assertArrayEquals(bytedef, ((GenericData.Fixed) newRec.get("fixedF1")).bytes());
Assert.assertArrayEquals(bytedef, ((GenericData.Fixed) newRec.get("fixedF2")).bytes());
Assert.assertArrayEquals(bytedef, ((GenericData.Fixed) newRec.get("fixedF3")).bytes());
Assert.assertArrayEquals(bytedef, ((GenericData.Fixed) newRec.get("fixedU")).bytes());
Assert.assertEquals("S", newRec.get("enumF").toString());
Assert.assertEquals("SS", newRec.get("enumU").toString());
@SuppressWarnings("unchecked")
Map<CharSequence, CharSequence> map = (Map<CharSequence, CharSequence>) newRec.get("mapF");
Assert.assertEquals(mapdef.size(), map.size());
for (Map.Entry<CharSequence, CharSequence> e : map.entrySet()) {
Assert.assertEquals(mapdef.get(e.getKey().toString()), e.getValue().toString());
}
Assert.assertEquals(newRec.get("mapF"), newRec.get("mapU"));
@SuppressWarnings("unchecked")
GenericData.Array<CharSequence> arr = (GenericData.Array<CharSequence>) newRec.get("arrayF");
Assert.assertEquals(arrdef.size(), arr.size());
for (CharSequence c : arr) {
Assert.assertTrue(arrdef.contains(c.toString()));
}
Assert.assertEquals(newRec.get("arrF"), newRec.get("arrU"));
Assert.assertEquals(recdef, newRec.get("recordF"));
Assert.assertEquals(recdef2, newRec.get("recordU"));
Assert.assertEquals("S", newRec.get("byName").toString());
}
@Test(expected = SchemaBuilderException.class)
public void testBadDefault() {
SchemaBuilder.record("r").fields().name("f").type(Schema.create(Schema.Type.INT)).withDefault(new Object())
.endRecord();
}
@Test
public void testUnionFieldBuild() {
SchemaBuilder.record("r").fields().name("allUnion").type().unionOf().booleanType().and().intType().and().longType()
.and().floatType().and().doubleType().and().stringType().and().bytesType().and().nullType().and().fixed("Fix")
.size(1).and().enumeration("Enu").symbols("Q").and().array().items().intType().and().map().values().longType()
.and().record("Rec").fields().name("one").type("Fix").noDefault().endRecord().endUnion().booleanDefault(false)
.endRecord();
}
@Test
public void testDefaults() throws IOException {
Schema writeSchema = SchemaBuilder.record("r").fields().name("requiredInt").type().intType().noDefault()
.name("optionalInt").type().optional().intType().name("nullableIntWithDefault").type().nullable().intType()
.intDefault(3).endRecord();
GenericData.Record rec1 = new GenericRecordBuilder(writeSchema).set("requiredInt", 1).build();
Assert.assertEquals(1, rec1.get("requiredInt"));
Assert.assertEquals(null, rec1.get("optionalInt"));
Assert.assertEquals(3, rec1.get("nullableIntWithDefault"));
GenericData.Record rec2 = new GenericRecordBuilder(writeSchema).set("requiredInt", 1).set("optionalInt", 2)
.set("nullableIntWithDefault", 13).build();
Assert.assertEquals(1, rec2.get("requiredInt"));
Assert.assertEquals(2, rec2.get("optionalInt"));
Assert.assertEquals(13, rec2.get("nullableIntWithDefault"));
// write to file
File file = new File(DIR.getRoot().getPath(), "testDefaults.avro");
try (DataFileWriter<Object> writer = new DataFileWriter<>(new GenericDatumWriter<>())) {
writer.create(writeSchema, file);
writer.append(rec1);
writer.append(rec2);
}
Schema readSchema = SchemaBuilder.record("r").fields().name("requiredInt").type().intType().noDefault()
.name("optionalInt").type().optional().intType().name("nullableIntWithDefault").type().nullable().intType()
.intDefault(3).name("newOptionalInt").type().optional().intType().name("newNullableIntWithDefault").type()
.nullable().intType().intDefault(5).endRecord();
DataFileReader<GenericData.Record> reader = new DataFileReader<>(file,
new GenericDatumReader<>(writeSchema, readSchema));
GenericData.Record rec1read = reader.iterator().next();
Assert.assertEquals(1, rec1read.get("requiredInt"));
Assert.assertNull(rec1read.get("optionalInt"));
Assert.assertEquals(3, rec1read.get("nullableIntWithDefault"));
Assert.assertNull(rec1read.get("newOptionalInt"));
Assert.assertEquals(5, rec1read.get("newNullableIntWithDefault"));
GenericData.Record rec2read = reader.iterator().next();
Assert.assertEquals(1, rec2read.get("requiredInt"));
Assert.assertEquals(2, rec2read.get("optionalInt"));
Assert.assertEquals(13, rec2read.get("nullableIntWithDefault"));
Assert.assertNull(rec2read.get("newOptionalInt"));
Assert.assertEquals(5, rec2read.get("newNullableIntWithDefault"));
}
@Test
public void testDefaultTypes() {
Integer intDef = 1;
Long longDef = 2L;
Float floatDef = 3F;
Double doubleDef = 4D;
Schema schema = SchemaBuilder.record("r").fields().name("int").type().intType().intDefault(intDef).name("long")
.type().longType().longDefault(longDef).name("float").type().floatType().floatDefault(floatDef).name("double")
.type().doubleType().doubleDefault(doubleDef).endRecord();
Assert.assertEquals("int field default type or value mismatch", intDef, schema.getField("int").defaultVal());
Assert.assertEquals("long field default type or value mismatch", longDef, schema.getField("long").defaultVal());
Assert.assertEquals("float field default type or value mismatch", floatDef, schema.getField("float").defaultVal());
Assert.assertEquals("double field default type or value mismatch", doubleDef,
schema.getField("double").defaultVal());
}
}