io.prestosql.hadoop.$internal.org.apache.avro.SchemaBuilder Maven / Gradle / Ivy
Show all versions of hadoop-apache Show documentation
/**
* 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 io.prestosql.hadoop.$internal.org.apache.avro;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import io.prestosql.hadoop.$internal.org.apache.avro.Schema.Field;
import io.prestosql.hadoop.$internal.org.apache.avro.generic.GenericData;
import io.prestosql.hadoop.$internal.org.apache.avro.generic.GenericRecord;
import io.prestosql.hadoop.$internal.org.codehaus.jackson.JsonNode;
import io.prestosql.hadoop.$internal.org.codehaus.jackson.io.JsonStringEncoder;
import io.prestosql.hadoop.$internal.org.codehaus.jackson.map.ObjectMapper;
import io.prestosql.hadoop.$internal.org.codehaus.jackson.node.TextNode;
/**
*
* A fluent interface for building {@link Schema} instances. The flow of the API
* is designed to mimic the Avro Schema
* Specification
*
* For example, the below JSON schema and the fluent builder code to create it
* are very similar:
*
*
* {
* "type": "record",
* "name": "HandshakeRequest", "namespace":"io.prestosql.hadoop.$internal.org.apache.avro.ipc",
* "fields": [
* {"name": "clientHash",
* "type": {"type": "fixed", "name": "MD5", "size": 16}},
* {"name": "clientProtocol", "type": ["null", "string"]},
* {"name": "serverHash", "type": "MD5"},
* {"name": "meta", "type": ["null", {"type": "map", "values": "bytes"}]}
* ]
* }
*
*
*
* Schema schema = SchemaBuilder
* .record("HandshakeRequest").namespace("io.prestosql.hadoop.$internal.org.apache.avro.ipc)
* .fields()
* .name("clientHash").type().fixed("MD5").size(16).noDefault()
* .name("clientProtocol").type().nullable().stringType().noDefault()
* .name("serverHash").type("MD5")
* .name("meta").type().nullable().map().values().bytesType().noDefault()
* .endRecord();
*
*
*
* Usage Guide
* SchemaBuilder chains together many smaller builders and maintains nested
* context in order to mimic the Avro Schema specification. Every Avro type in
* JSON has required and optional JSON properties, as well as user-defined
* properties.
*
* Selecting and Building an Avro Type
* The API analogy for the right hand side of the Avro Schema JSON
*
* "type":
*
* 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.
*
* Primitive Types
* 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:
*
* {"type":"int"}
* {"type":{"name":"int"}}
* {"type":{"name":"int", "customProp":"val"}}
*
* The analogous code form for the above three JSON lines are the below
* three lines:
*
* .intType()
* .intBuilder().endInt()
* .intBuilder().prop("customProp", "val").endInt()
*
* 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.
* Named Types
* Avro named types have names, namespace, aliases, and doc. In this API
* these share a common parent, {@link NamespacedBuilder}.
* The builders for named types require a name to be constructed, and optional
* configuration via:
* {@link NamespacedBuilder#doc()}
* {@link NamespacedBuilder#namespace(String)}
* {@link NamespacedBuilder#aliases(String...)}
* {@link PropBuilder#prop(String, String)}
*
* Each named type completes configuration of the optional properties
* with its own method:
* {@link FixedBuilder#size(int)}
* {@link EnumBuilder#symbols(String...)}
* {@link RecordBuilder#fields()}
* Example use of a named type with all optional parameters:
*
* .enumeration("Suit").namespace("org.apache.test")
* .aliases("org.apache.test.OldSuit")
* .doc("CardSuits")
* .prop("customProp", "val")
* .symbols("SPADES", "HEARTS", "DIAMONDS", "CLUBS")
*
* Which is equivalent to the JSON:
*
* { "type":"enum",
* "name":"Suit", "namespace":"org.apache.test",
* "aliases":["org.apache.test.OldSuit"],
* "doc":"Card Suits",
* "customProp":"val",
* "symbols":["SPADES", "HEARTS", "DIAMONDS", "CLUBS"]
* }
*
* Nested Types
* 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 selects its nested type with {@link ArrayBuilder#items()}
* and {@link MapBuilder#values()}, respectively.
*
* Fields
* {@link RecordBuilder#fields()} returns a {@link FieldAssembler} for
* defining the fields of the record and completing it.
* Each field must have a name, specified via {@link FieldAssembler#name(String)},
* which returns a {@link FieldBuilder} for defining aliases, custom properties,
* and documentation of the field. After configuring these optional values for
* a field, the type is selected or built with {@link FieldBuilder#type()}.
*
* Fields have default values that must be specified to complete the field.
* {@link FieldDefault#noDefault()} is available for all field types, and
* a specific method is available for each type to use a default, for example
* {@link IntDefault#intDefault(int)}
*
* There are field shortcut methods on {@link FieldAssembler} for primitive types.
* These shortcuts create required, optional, and nullable fields, but do not
* support field aliases, doc, or custom properties.
*
* Unions
* 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:
*
* .unionOf()
* .fixed("IPv4").size(4).and()
* .fixed("IPv6").size(16).and()
* .nullType().endUnion()
*
* is equivalent to the Avro schema JSON:
*
* [
* {"type":"fixed", "name":"IPv4", "size":4},
* {"type":"fixed", "name":"IPv6", "size":16},
* "null"
* ]
*
* In a field context, the first type of a union defines what default type
* is allowed.
*
* 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:
*
* .unionOf().intType().and().nullType().endUnion()
* .nullable().intType()
*
* The below two field declarations are equivalent:
*
* .name("f").type().unionOf().nullType().and().longType().endUnion().nullDefault()
* .name("f").type().optional().longType()
*
*
* Explicit Types and Types by Name
* Types can also be specified explicitly by passing in a Schema, or by name:
*
* .type(Schema.create(Schema.Type.INT)) // explicitly specified
* .type("MD5") // reference by full name or short name
* .type("MD5", "io.prestosql.hadoop.$internal.org.apache.avro.test") // reference by name and namespace
*
* 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 union. To specify a name that has no namespace and ignore the inherited
* namespace, set the namespace to "".
*
* {@link SchemaBuilder#builder(String)} returns a type builder with a default
* namespace. {@link SchemaBuilder#builder()} returns a type builder with no
* default namespace.
*/
public class SchemaBuilder {
private SchemaBuilder() {
}
/**
* Create a builder for Avro schemas.
*/
public static TypeBuilder builder() {
return new TypeBuilder(new SchemaCompletion(), new NameContext());
}
/**
* Create a builder for Avro schemas with a default namespace. Types created
* without namespaces will inherit the namespace provided.
*/
public static TypeBuilder builder(String namespace) {
return new TypeBuilder(new SchemaCompletion(),
new NameContext().namespace(namespace));
}
/**
* Create a builder for an Avro record with the specified name.
* This is equivalent to:
*
* builder().record(name);
*
* @param name the record name
*/
public static RecordBuilder record(String name) {
return builder().record(name);
}
/**
* Create a builder for an Avro enum with the specified name and symbols (values).
* This is equivalent to:
*
* builder().enumeration(name);
*
* @param name the enum name
*/
public static EnumBuilder enumeration(String name) {
return builder().enumeration(name);
}
/**
* Create a builder for an Avro fixed type with the specified name and size.
* This is equivalent to:
*
* builder().fixed(name);
*
* @param name the fixed name
*/
public static FixedBuilder fixed(String name) {
return builder().fixed(name);
}
/**
* Create a builder for an Avro array
* This is equivalent to:
*
* builder().array();
*
*/
public static ArrayBuilder array() {
return builder().array();
}
/**
* Create a builder for an Avro map
* This is equivalent to:
*
* builder().map();
*
*/
public static MapBuilder map() {
return builder().map();
}
/**
* Create a builder for an Avro union
* This is equivalent to:
*
* builder().unionOf();
*
*/
public static BaseTypeBuilder> unionOf() {
return builder().unionOf();
}
/**
* Create a builder for a union of a type and null.
* This is a shortcut for:
*
* builder().nullable();
*
* and the following two lines are equivalent:
*
* nullable().intType();
*
*
* unionOf().intType().and().nullType().endUnion();
*
*/
public static BaseTypeBuilder nullable() {
return builder().nullable();
}
/**
* An abstract builder for all Avro types. All Avro types
* can have arbitrary string key-value properties.
*/
public static abstract class PropBuilder> {
private Map props = null;
protected PropBuilder() {
}
/**
* Set name-value pair properties for this type or field.
*/
public final S prop(String name, String val) {
return prop(name, TextNode.valueOf(val));
}
// for internal use by the Parser
final S prop(String name, JsonNode val) {
if(!hasProps()) {
props = new HashMap();
}
props.put(name, val);
return self();
}
private boolean hasProps() {
return (props != null);
}
final T addPropsTo(T jsonable) {
if (hasProps()) {
for(Map.Entry prop : props.entrySet()) {
jsonable.addProp(prop.getKey(), prop.getValue());
}
}
return jsonable;
}
/** a self-type for chaining builder subclasses. Concrete subclasses
* must return 'this' **/
protected abstract S self();
}
/**
* An abstract type that provides builder methods for configuring the name,
* doc, and aliases of all Avro types that have names (fields, Fixed, Record,
* and Enum).
*
* All Avro named types and fields have 'doc', 'aliases', and 'name'
* components. 'name' is required, and provided to this builder. 'doc' and
* 'alises' are optional.
*/
public static abstract class NamedBuilder> extends
PropBuilder {
private final String name;
private final NameContext names;
private String doc;
private String[] aliases;
protected NamedBuilder(NameContext names, String name) {
checkRequired(name, "Type must have a name");
this.names = names;
this.name = name;
}
/** configure this type's optional documentation string **/
public final S doc(String doc) {
this.doc = doc;
return self();
}
/** configure this type's optional name aliases **/
public final S aliases(String... aliases) {
this.aliases = aliases;
return self();
}
final String doc() {
return doc;
}
final String name() {
return name;
}
final NameContext names() {
return names;
}
final Schema addAliasesTo(Schema schema) {
if (null != aliases) {
for (String alias : aliases) {
schema.addAlias(alias);
}
}
return schema;
}
final Field addAliasesTo(Field field) {
if (null != aliases) {
for (String alias : aliases) {
field.addAlias(alias);
}
}
return field;
}
}
/**
* An abstract type that provides builder methods for configuring the
* namespace for all Avro types that have namespaces (Fixed, Record, and
* Enum).
*/
public static abstract class NamespacedBuilder>
extends NamedBuilder {
private final Completion context;
private String namespace;
protected NamespacedBuilder(Completion context, NameContext names,
String name) {
super(names, name);
this.context = context;
}
/**
* Set the namespace of this type. To clear the namespace, set empty string.
*
* When the namespace is null or unset, the namespace of the type defaults
* to the namespace of the enclosing context.
**/
public final S namespace(String namespace) {
this.namespace = namespace;
return self();
}
final String space() {
if (null == namespace) {
return names().namespace;
}
return namespace;
}
final Schema completeSchema(Schema schema) {
addPropsTo(schema);
addAliasesTo(schema);
names().put(schema);
return schema;
}
final Completion context() {
return context;
}
}
/**
* An abstraction for sharing code amongst all primitive type builders.
*/
private static abstract class PrimitiveBuilder>
extends PropBuilder {
private final Completion context;
private final Schema immutable;
protected PrimitiveBuilder(Completion context, NameContext names,
Schema.Type type) {
this.context = context;
this.immutable = names.getFullname(type.getName());
}
private R end() {
Schema schema = immutable;
if (super.hasProps()) {
schema = Schema.create(immutable.getType());
addPropsTo(schema);
}
return context.complete(schema);
}
}
/**
* Builds an Avro boolean type with optional properties. Set properties with
* {@link #prop(String, String)}, and finalize with {@link #endBoolean()}
**/
public static final class BooleanBuilder extends
PrimitiveBuilder> {
private BooleanBuilder(Completion context, NameContext names) {
super(context, names, Schema.Type.BOOLEAN);
}
private static BooleanBuilder create(Completion context,
NameContext names) {
return new BooleanBuilder(context, names);
}
@Override
protected BooleanBuilder self() {
return this;
}
/** complete building this type, return control to context **/
public R endBoolean() {
return super.end();
}
}
/**
* Builds an Avro int type with optional properties. Set properties with
* {@link #prop(String, String)}, and finalize with {@link #endInt()}
**/
public static final class IntBuilder extends
PrimitiveBuilder> {
private IntBuilder(Completion context, NameContext names) {
super(context, names, Schema.Type.INT);
}
private static IntBuilder create(Completion context,
NameContext names) {
return new IntBuilder(context, names);
}
@Override
protected IntBuilder self() {
return this;
}
/** complete building this type, return control to context **/
public R endInt() {
return super.end();
}
}
/**
* Builds an Avro long type with optional properties. Set properties with
* {@link #prop(String, String)}, and finalize with {@link #endLong()}
**/
public static final class LongBuilder extends
PrimitiveBuilder> {
private LongBuilder(Completion context, NameContext names) {
super(context, names, Schema.Type.LONG);
}
private static LongBuilder create(Completion context,
NameContext names) {
return new LongBuilder(context, names);
}
@Override
protected LongBuilder self() {
return this;
}
/** complete building this type, return control to context **/
public R endLong() {
return super.end();
}
}
/**
* Builds an Avro float type with optional properties. Set properties with
* {@link #prop(String, String)}, and finalize with {@link #endFloat()}
**/
public static final class FloatBuilder extends
PrimitiveBuilder> {
private FloatBuilder(Completion context, NameContext names) {
super(context, names, Schema.Type.FLOAT);
}
private static FloatBuilder create(Completion context,
NameContext names) {
return new FloatBuilder(context, names);
}
@Override
protected FloatBuilder self() {
return this;
}
/** complete building this type, return control to context **/
public R endFloat() {
return super.end();
}
}
/**
* Builds an Avro double type with optional properties. Set properties with
* {@link #prop(String, String)}, and finalize with {@link #endDouble()}
**/
public static final class DoubleBuilder extends
PrimitiveBuilder> {
private DoubleBuilder(Completion context, NameContext names) {
super(context, names, Schema.Type.DOUBLE);
}
private static DoubleBuilder create(Completion context,
NameContext names) {
return new DoubleBuilder(context, names);
}
@Override
protected DoubleBuilder self() {
return this;
}
/** complete building this type, return control to context **/
public R endDouble() {
return super.end();
}
}
/**
* Builds an Avro string type with optional properties. Set properties with
* {@link #prop(String, String)}, and finalize with {@link #endString()}
**/
public static final class StringBldr extends
PrimitiveBuilder> {
private StringBldr(Completion context, NameContext names) {
super(context, names, Schema.Type.STRING);
}
private static StringBldr create(Completion context,
NameContext names) {
return new StringBldr(context, names);
}
@Override
protected StringBldr self() {
return this;
}
/** complete building this type, return control to context **/
public R endString() {
return super.end();
}
}
/**
* Builds an Avro bytes type with optional properties. Set properties with
* {@link #prop(String, String)}, and finalize with {@link #endBytes()}
**/
public static final class BytesBuilder extends
PrimitiveBuilder> {
private BytesBuilder(Completion context, NameContext names) {
super(context, names, Schema.Type.BYTES);
}
private static BytesBuilder create(Completion context,
NameContext names) {
return new BytesBuilder(context, names);
}
@Override
protected BytesBuilder self() {
return this;
}
/** complete building this type, return control to context **/
public R endBytes() {
return super.end();
}
}
/**
* Builds an Avro null type with optional properties. Set properties with
* {@link #prop(String, String)}, and finalize with {@link #endNull()}
**/
public static final class NullBuilder extends
PrimitiveBuilder> {
private NullBuilder(Completion context, NameContext names) {
super(context, names, Schema.Type.NULL);
}
private static NullBuilder create(Completion context,
NameContext names) {
return new NullBuilder(context, names);
}
@Override
protected NullBuilder self() {
return this;
}
/** complete building this type, return control to context **/
public R endNull() {
return super.end();
}
}
/**
* Builds an Avro Fixed type with optional properties, namespace, doc, and
* aliases.
*
* Set properties with {@link #prop(String, String)}, namespace with
* {@link #namespace(String)}, doc with {@link #doc(String)}, and aliases with
* {@link #aliases(String[])}.
*
* The Fixed schema is finalized when its required size is set via
* {@link #size(int)}.
**/
public static final class FixedBuilder extends
NamespacedBuilder> {
private FixedBuilder(Completion context, NameContext names, String name) {
super(context, names, name);
}
private static FixedBuilder create(Completion context,
NameContext names, String name) {
return new FixedBuilder(context, names, name);
}
@Override
protected FixedBuilder self() {
return this;
}
/** Configure this fixed type's size, and end its configuration. **/
public R size(int size) {
Schema schema = Schema.createFixed(name(), super.doc(), space(), size);
completeSchema(schema);
return context().complete(schema);
}
}
/**
* Builds an Avro Enum type with optional properties, namespace, doc, and
* aliases.
*
* Set properties with {@link #prop(String, String)}, namespace with
* {@link #namespace(String)}, doc with {@link #doc(String)}, and aliases with
* {@link #aliases(String[])}.
*
* The Enum schema is finalized when its required symbols are set via
* {@link #symbols(String[])}.
**/
public static final class EnumBuilder extends
NamespacedBuilder> {
private EnumBuilder(Completion context, NameContext names, String name) {
super(context, names, name);
}
private static EnumBuilder create(Completion context,
NameContext names, String name) {
return new EnumBuilder(context, names, name);
}
@Override
protected EnumBuilder self() {
return this;
}
/** Configure this enum type's symbols, and end its configuration. **/
public R symbols(String... symbols) {
Schema schema = Schema.createEnum(name(), doc(), space(),
Arrays.asList(symbols));
completeSchema(schema);
return context().complete(schema);
}
}
/**
* Builds an Avro Map type with optional properties.
*
* Set properties with {@link #prop(String, String)}.
*
* The Map schema's properties are finalized when {@link #values()} or
* {@link #values(Schema)} is called.
**/
public static final class MapBuilder extends PropBuilder> {
private final Completion context;
private final NameContext names;
private MapBuilder(Completion context, NameContext names) {
this.context = context;
this.names = names;
}
private static MapBuilder create(Completion context,
NameContext names) {
return new MapBuilder(context, names);
}
@Override
protected MapBuilder self() {
return this;
}
/**
* Return a type builder for configuring the map's nested values schema.
* This builder will return control to the map's enclosing context when
* complete.
**/
public TypeBuilder values() {
return new TypeBuilder(new MapCompletion(this, context), names);
}
/**
* Complete configuration of this map, setting the schema of the map values
* to the schema provided. Returns control to the enclosing context.
**/
public R values(Schema valueSchema) {
return new MapCompletion(this, context).complete(valueSchema);
}
}
/**
* Builds an Avro Array type with optional properties.
*
* Set properties with {@link #prop(String, String)}.
*
* The Array schema's properties are finalized when {@link #items()} or
* {@link #items(Schema)} is called.
**/
public static final class ArrayBuilder extends
PropBuilder> {
private final Completion context;
private final NameContext names;
public ArrayBuilder(Completion context, NameContext names) {
this.context = context;
this.names = names;
}
private static ArrayBuilder create(Completion context,
NameContext names) {
return new ArrayBuilder(context, names);
}
@Override
protected ArrayBuilder self() {
return this;
}
/**
* Return a type builder for configuring the array's nested items schema.
* This builder will return control to the array's enclosing context when
* complete.
**/
public TypeBuilder items() {
return new TypeBuilder(new ArrayCompletion(this, context), names);
}
/**
* Complete configuration of this array, setting the schema of the array
* items to the schema provided. Returns control to the enclosing context.
**/
public R items(Schema itemsSchema) {
return new ArrayCompletion(this, context).complete(itemsSchema);
}
}
/**
* internal class for passing the naming context around. This allows for the
* following:
* Cache and re-use primitive schemas when they do not set
* properties.
* Provide a default namespace for nested contexts (as
* the JSON Schema spec does).
* Allow previously defined named types or primitive types
* to be referenced by name.
**/
private static class NameContext {
private static final Set PRIMITIVES = new HashSet();
{
PRIMITIVES.add("null");
PRIMITIVES.add("boolean");
PRIMITIVES.add("int");
PRIMITIVES.add("long");
PRIMITIVES.add("float");
PRIMITIVES.add("double");
PRIMITIVES.add("bytes");
PRIMITIVES.add("string");
}
private final HashMap schemas;
private final String namespace;
private NameContext() {
this.schemas = new HashMap();
this.namespace = null;
schemas.put("null", Schema.create(Schema.Type.NULL));
schemas.put("boolean", Schema.create(Schema.Type.BOOLEAN));
schemas.put("int", Schema.create(Schema.Type.INT));
schemas.put("long", Schema.create(Schema.Type.LONG));
schemas.put("float", Schema.create(Schema.Type.FLOAT));
schemas.put("double", Schema.create(Schema.Type.DOUBLE));
schemas.put("bytes", Schema.create(Schema.Type.BYTES));
schemas.put("string", Schema.create(Schema.Type.STRING));
}
private NameContext(HashMap schemas, String namespace) {
this.schemas = schemas;
this.namespace = "".equals(namespace) ? null : namespace;
}
private NameContext namespace(String namespace) {
return new NameContext(schemas, namespace);
}
private Schema get(String name, String namespace) {
return getFullname(resolveName(name, namespace));
}
private Schema getFullname(String fullName) {
Schema schema = schemas.get(fullName);
if(schema == null) {
throw new SchemaParseException("Undefined name: " + fullName);
}
return schema;
}
private void put(Schema schema) {
String fullName = schema.getFullName();
if(schemas.containsKey(fullName)){
throw new SchemaParseException("Can't redefine: " + fullName);
}
schemas.put(fullName, schema);
}
private String resolveName(String name, String space) {
if (PRIMITIVES.contains(name) && space == null) {
return name;
}
int lastDot = name.lastIndexOf('.');
if (lastDot < 0) { // short name
if (space == null) {
space = namespace;
}
if (space != null && !"".equals(space)) {
return space + "." + name;
}
}
return name;
}
}
/**
* A common API for building types within a context. BaseTypeBuilder can build
* all types other than Unions. {@link TypeBuilder} can additionally build
* Unions.
*
* The builder has two contexts:
* A naming context provides a default namespace and allows for previously
* defined named types to be referenced from {@link #type(String)}
* A completion context representing the scope that the builder was
* created in. A builder created in a nested context (for example,
* {@link MapBuilder#values()} will have a completion context assigned by the
* {@link MapBuilder}
**/
public static class BaseTypeBuilder {
private final Completion context;
private final NameContext names;
private BaseTypeBuilder(Completion context, NameContext names) {
this.context = context;
this.names = names;
}
/** Use the schema provided as the type. **/
public final R type(Schema schema) {
return context.complete(schema);
}
/**
* Look up the type by name. This type must be previously defined in the
* context of this builder.
*
* The name may be fully qualified or a short name. If it is a short name,
* the default namespace of the current context will additionally be
* searched.
**/
public final R type(String name) {
return type(name, null);
}
/**
* Look up the type by name and namespace. This type must be previously
* defined in the context of this builder.
*
* The name may be fully qualified or a short name. If it is a fully
* qualified name, the namespace provided is ignored. If it is a short name,
* the namespace provided is used if not null, else the default namespace of
* the current context will be used.
**/
public final R type(String name, String namespace) {
return type(names.get(name, namespace));
}
/**
* A plain boolean type without custom properties. This is equivalent to:
*
* booleanBuilder().endBoolean();
*
*/
public final R booleanType() {
return booleanBuilder().endBoolean();
}
/**
* Build a boolean type that can set custom properties. If custom properties
* are not needed it is simpler to use {@link #booleanType()}.
*/
public final BooleanBuilder booleanBuilder() {
return BooleanBuilder.create(context, names);
}
/**
* A plain int type without custom properties. This is equivalent to:
*
* intBuilder().endInt();
*
*/
public final R intType() {
return intBuilder().endInt();
}
/**
* Build an int type that can set custom properties. If custom properties
* are not needed it is simpler to use {@link #intType()}.
*/
public final IntBuilder intBuilder() {
return IntBuilder.create(context, names);
}
/**
* A plain long type without custom properties. This is equivalent to:
*
* longBuilder().endLong();
*
*/
public final R longType() {
return longBuilder().endLong();
}
/**
* Build a long type that can set custom properties. If custom properties
* are not needed it is simpler to use {@link #longType()}.
*/
public final LongBuilder longBuilder() {
return LongBuilder.create(context, names);
}
/**
* A plain float type without custom properties. This is equivalent to:
*
* floatBuilder().endFloat();
*
*/
public final R floatType() {
return floatBuilder().endFloat();
}
/**
* Build a float type that can set custom properties. If custom properties
* are not needed it is simpler to use {@link #floatType()}.
*/
public final FloatBuilder floatBuilder() {
return FloatBuilder.create(context, names);
}
/**
* A plain double type without custom properties. This is equivalent to:
*
* doubleBuilder().endDouble();
*
*/
public final R doubleType() {
return doubleBuilder().endDouble();
}
/**
* Build a double type that can set custom properties. If custom properties
* are not needed it is simpler to use {@link #doubleType()}.
*/
public final DoubleBuilder doubleBuilder() {
return DoubleBuilder.create(context, names);
}
/**
* A plain string type without custom properties. This is equivalent to:
*
* stringBuilder().endString();
*
*/
public final R stringType() {
return stringBuilder().endString();
}
/**
* Build a string type that can set custom properties. If custom properties
* are not needed it is simpler to use {@link #stringType()}.
*/
public final StringBldr stringBuilder() {
return StringBldr.create(context, names);
}
/**
* A plain bytes type without custom properties. This is equivalent to:
*
* bytesBuilder().endBytes();
*
*/
public final R bytesType() {
return bytesBuilder().endBytes();
}
/**
* Build a bytes type that can set custom properties. If custom properties
* are not needed it is simpler to use {@link #bytesType()}.
*/
public final BytesBuilder bytesBuilder() {
return BytesBuilder.create(context, names);
}
/**
* A plain null type without custom properties. This is equivalent to:
*
* nullBuilder().endNull();
*
*/
public final R nullType() {
return nullBuilder().endNull();
}
/**
* Build a null type that can set custom properties. If custom properties
* are not needed it is simpler to use {@link #nullType()}.
*/
public final NullBuilder nullBuilder() {
return NullBuilder.create(context, names);
}
/** Build an Avro map type Example usage:
*
* map().values().intType()
*
* Equivalent to Avro JSON Schema:
*
* {"type":"map", "values":"int"}
*
**/
public final MapBuilder map() {
return MapBuilder.create(context, names);
}
/** Build an Avro array type Example usage:
*
* array().items().longType()
*
* Equivalent to Avro JSON Schema:
*
* {"type":"array", "values":"long"}
*
**/
public final ArrayBuilder array() {
return ArrayBuilder.create(context, names);
}
/** Build an Avro fixed type. Example usage:
*
* fixed("com.foo.IPv4").size(4)
*
* Equivalent to Avro JSON Schema:
*
* {"type":"fixed", "name":"com.foo.IPv4", "size":4}
*
**/
public final FixedBuilder fixed(String name) {
return FixedBuilder.create(context, names, name);
}
/** Build an Avro enum type. Example usage:
*
* enumeration("Suits").namespace("org.cards").doc("card suit names")
* .symbols("HEART", "SPADE", "DIAMOND", "CLUB")
*
* Equivalent to Avro JSON Schema:
*
* {"type":"enum", "name":"Suits", "namespace":"org.cards",
* "doc":"card suit names", "symbols":[
* "HEART", "SPADE", "DIAMOND", "CLUB"]}
*
**/
public final EnumBuilder enumeration(String name) {
return EnumBuilder.create(context, names, name);
}
/** Build an Avro record type. Example usage:
*
* record("com.foo.Foo").fields()
* .name("field1").typeInt().intDefault(1)
* .name("field2").typeString().noDefault()
* .name("field3").optional().typeFixed("FooFixed").size(4)
* .endRecord()
*
* Equivalent to Avro JSON Schema:
*
* {"type":"record", "name":"com.foo.Foo", "fields": [
* {"name":"field1", "type":"int", "default":1},
* {"name":"field2", "type":"string"},
* {"name":"field3", "type":[
* null, {"type":"fixed", "name":"FooFixed", "size":4}
* ]}
* ]}
*
**/
public final RecordBuilder record(String name) {
return RecordBuilder.create(context, names, name);
}
/** Build an Avro union schema type. Example usage:
* unionOf().stringType().and().bytesType().endUnion()
**/
protected BaseTypeBuilder> unionOf() {
return UnionBuilder.create(context, names);
}
/** A shortcut for building a union of a type and null.
*
* For example, the code snippets below are equivalent:
* nullable().booleanType()
* unionOf().booleanType().and().nullType().endUnion()
**/
protected BaseTypeBuilder nullable() {
return new BaseTypeBuilder(new NullableCompletion(context), names);
}
}
/** A Builder for creating any Avro schema type.
**/
public static final class TypeBuilder extends BaseTypeBuilder {
private TypeBuilder(Completion context, NameContext names) {
super(context, names);
}
@Override
public BaseTypeBuilder> unionOf() {
return super.unionOf();
}
@Override
public BaseTypeBuilder nullable() {
return super.nullable();
}
}
/** A special builder for unions. Unions cannot nest unions directly **/
private static final class UnionBuilder extends
BaseTypeBuilder> {
private UnionBuilder(Completion context, NameContext names) {
this(context, names, new ArrayList());
}
private static UnionBuilder create(Completion context, NameContext names) {
return new UnionBuilder(context, names);
}
private UnionBuilder(Completion context, NameContext names, List schemas) {
super(new UnionCompletion(context, names, schemas), names);
}
}
/**
* A special Builder for Record fields. The API is very similar to
* {@link BaseTypeBuilder}. However, fields have their own names, properties,
* and default values.
*
* The methods on this class create builder instances that return their
* control to the {@link FieldAssembler} of the enclosing record context after
* configuring a default for the field.
*
* For example, an int field with default value 1:
*
* intSimple().withDefault(1);
*
* or an array with items that are optional int types:
*
* array().items().optional().intType();
*
*/
public static class BaseFieldTypeBuilder {
protected final FieldBuilder bldr;
protected final NameContext names;
private final CompletionWrapper wrapper;
protected BaseFieldTypeBuilder(FieldBuilder bldr, CompletionWrapper wrapper) {
this.bldr = bldr;
this.names = bldr.names();
this.wrapper = wrapper;
}
/**
* A plain boolean type without custom properties. This is equivalent to:
*
* booleanBuilder().endBoolean();
*
*/
public final BooleanDefault booleanType() {
return booleanBuilder().endBoolean();
}
/**
* Build a boolean type that can set custom properties. If custom properties
* are not needed it is simpler to use {@link #booleanType()}.
*/
public final BooleanBuilder> booleanBuilder() {
return BooleanBuilder.create(wrap(new BooleanDefault(bldr)), names);
}
/**
* A plain int type without custom properties. This is equivalent to:
*
* intBuilder().endInt();
*
*/
public final IntDefault intType() {
return intBuilder().endInt();
}
/**
* Build an int type that can set custom properties. If custom properties
* are not needed it is simpler to use {@link #intType()}.
*/
public final IntBuilder> intBuilder() {
return IntBuilder.create(wrap(new IntDefault(bldr)), names);
}
/**
* A plain long type without custom properties. This is equivalent to:
*
* longBuilder().endLong();
*
*/
public final LongDefault longType() {
return longBuilder().endLong();
}
/**
* Build a long type that can set custom properties. If custom properties
* are not needed it is simpler to use {@link #longType()}.
*/
public final LongBuilder> longBuilder() {
return LongBuilder.create(wrap(new LongDefault(bldr)), names);
}
/**
* A plain float type without custom properties. This is equivalent to:
*
* floatBuilder().endFloat();
*
*/
public final FloatDefault floatType() {
return floatBuilder().endFloat();
}
/**
* Build a float type that can set custom properties. If custom properties
* are not needed it is simpler to use {@link #floatType()}.
*/
public final FloatBuilder> floatBuilder() {
return FloatBuilder.create(wrap(new FloatDefault(bldr)), names);
}
/**
* A plain double type without custom properties. This is equivalent to:
*
* doubleBuilder().endDouble();
*
*/
public final DoubleDefault doubleType() {
return doubleBuilder().endDouble();
}
/**
* Build a double type that can set custom properties. If custom properties
* are not needed it is simpler to use {@link #doubleType()}.
*/
public final DoubleBuilder> doubleBuilder() {
return DoubleBuilder.create(wrap(new DoubleDefault(bldr)), names);
}
/**
* A plain string type without custom properties. This is equivalent to:
*
* stringBuilder().endString();
*
*/
public final StringDefault stringType() {
return stringBuilder().endString();
}
/**
* Build a string type that can set custom properties. If custom properties
* are not needed it is simpler to use {@link #stringType()}.
*/
public final StringBldr> stringBuilder() {
return StringBldr.create(wrap(new StringDefault(bldr)), names);
}
/**
* A plain bytes type without custom properties. This is equivalent to:
*
* bytesBuilder().endBytes();
*
*/
public final BytesDefault bytesType() {
return bytesBuilder().endBytes();
}
/**
* Build a bytes type that can set custom properties. If custom properties
* are not needed it is simpler to use {@link #bytesType()}.
*/
public final BytesBuilder> bytesBuilder() {
return BytesBuilder.create(wrap(new BytesDefault(bldr)), names);
}
/**
* A plain null type without custom properties. This is equivalent to:
*
* nullBuilder().endNull();
*
*/
public final NullDefault nullType() {
return nullBuilder().endNull();
}
/**
* Build a null type that can set custom properties. If custom properties
* are not needed it is simpler to use {@link #nullType()}.
*/
public final NullBuilder> nullBuilder() {
return NullBuilder.create(wrap(new NullDefault(bldr)), names);
}
/** Build an Avro map type **/
public final MapBuilder> map() {
return MapBuilder.create(wrap(new MapDefault(bldr)), names);
}
/** Build an Avro array type **/
public final ArrayBuilder> array() {
return ArrayBuilder.create(wrap(new ArrayDefault(bldr)), names);
}
/** Build an Avro fixed type. **/
public final FixedBuilder> fixed(String name) {
return FixedBuilder.create(wrap(new FixedDefault(bldr)), names, name);
}
/** Build an Avro enum type. **/
public final EnumBuilder> enumeration(String name) {
return EnumBuilder.create(wrap(new EnumDefault(bldr)), names, name);
}
/** Build an Avro record type. **/
public final RecordBuilder> record(String name) {
return RecordBuilder.create(wrap(new RecordDefault(bldr)), names, name);
}
private Completion wrap(
Completion completion) {
if (wrapper != null) {
return wrapper.wrap(completion);
}
return completion;
}
}
/** FieldTypeBuilder adds {@link #unionOf()}, {@link #nullable()}, and {@link #optional()}
* to BaseFieldTypeBuilder. **/
public static final class FieldTypeBuilder extends BaseFieldTypeBuilder {
private FieldTypeBuilder(FieldBuilder bldr) {
super(bldr, null);
}
/** Build an Avro union schema type. **/
public UnionFieldTypeBuilder unionOf() {
return new UnionFieldTypeBuilder(bldr);
}
/**
* A shortcut for building a union of a type and null, with an optional default
* value of the non-null type.
*
* For example, the two code snippets below are equivalent:
* nullable().booleanType().booleanDefault(true)
* unionOf().booleanType().and().nullType().endUnion().booleanDefault(true)
**/
public BaseFieldTypeBuilder nullable() {
return new BaseFieldTypeBuilder(bldr, new NullableCompletionWrapper());
}
/**
* A shortcut for building a union of null and a type, with a null default.
*
* For example, the two code snippets below are equivalent:
* optional().booleanType()
* unionOf().nullType().and().booleanType().endUnion().nullDefault()
*/
public BaseTypeBuilder> optional() {
return new BaseTypeBuilder>(
new OptionalCompletion(bldr), names);
}
}
/** Builder for a union field. The first type in the union corresponds
* to the possible default value type.
*/
public static final class UnionFieldTypeBuilder {
private final FieldBuilder bldr;
private final NameContext names;
private UnionFieldTypeBuilder(FieldBuilder bldr) {
this.bldr = bldr;
this.names = bldr.names();
}
/**
* A plain boolean type without custom properties. This is equivalent to:
*
* booleanBuilder().endBoolean();
*
*/
public UnionAccumulator> booleanType() {
return booleanBuilder().endBoolean();
}
/**
* Build a boolean type that can set custom properties. If custom properties
* are not needed it is simpler to use {@link #booleanType()}.
*/
public BooleanBuilder>> booleanBuilder() {
return BooleanBuilder.create(completion(new BooleanDefault(bldr)), names);
}
/**
* A plain int type without custom properties. This is equivalent to:
*
* intBuilder().endInt();
*
*/
public UnionAccumulator> intType() {
return intBuilder().endInt();
}
/**
* Build an int type that can set custom properties. If custom properties
* are not needed it is simpler to use {@link #intType()}.
*/
public IntBuilder>> intBuilder() {
return IntBuilder.create(completion(new IntDefault(bldr)), names);
}
/**
* A plain long type without custom properties. This is equivalent to:
*
* longBuilder().endLong();
*
*/
public UnionAccumulator> longType() {
return longBuilder().endLong();
}
/**
* Build a long type that can set custom properties. If custom properties
* are not needed it is simpler to use {@link #longType()}.
*/
public LongBuilder>> longBuilder() {
return LongBuilder.create(completion(new LongDefault(bldr)), names);
}
/**
* A plain float type without custom properties. This is equivalent to:
*
* floatBuilder().endFloat();
*
*/
public UnionAccumulator> floatType() {
return floatBuilder().endFloat();
}
/**
* Build a float type that can set custom properties. If custom properties
* are not needed it is simpler to use {@link #floatType()}.
*/
public FloatBuilder>> floatBuilder() {
return FloatBuilder.create(completion(new FloatDefault(bldr)), names);
}
/**
* A plain double type without custom properties. This is equivalent to:
*
* doubleBuilder().endDouble();
*
*/
public UnionAccumulator> doubleType() {
return doubleBuilder().endDouble();
}
/**
* Build a double type that can set custom properties. If custom properties
* are not needed it is simpler to use {@link #doubleType()}.
*/
public DoubleBuilder>> doubleBuilder() {
return DoubleBuilder.create(completion(new DoubleDefault(bldr)), names);
}
/**
* A plain string type without custom properties. This is equivalent to:
*
* stringBuilder().endString();
*
*/
public UnionAccumulator> stringType() {
return stringBuilder().endString();
}
/**
* Build a string type that can set custom properties. If custom properties
* are not needed it is simpler to use {@link #stringType()}.
*/
public StringBldr>> stringBuilder() {
return StringBldr.create(completion(new StringDefault(bldr)), names);
}
/**
* A plain bytes type without custom properties. This is equivalent to:
*
* bytesBuilder().endBytes();
*
*/
public UnionAccumulator> bytesType() {
return bytesBuilder().endBytes();
}
/**
* Build a bytes type that can set custom properties. If custom properties
* are not needed it is simpler to use {@link #bytesType()}.
*/
public BytesBuilder>> bytesBuilder() {
return BytesBuilder.create(completion(new BytesDefault(bldr)), names);
}
/**
* A plain null type without custom properties. This is equivalent to:
*
* nullBuilder().endNull();
*
*/
public UnionAccumulator> nullType() {
return nullBuilder().endNull();
}
/**
* Build a null type that can set custom properties. If custom properties
* are not needed it is simpler to use {@link #nullType()}.
*/
public NullBuilder>> nullBuilder() {
return NullBuilder.create(completion(new NullDefault(bldr)), names);
}
/** Build an Avro map type **/
public MapBuilder