Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* 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 com.facebook.presto.hive.$internal.com.fasterxml.jackson.core.JsonFactory;
import com.facebook.presto.hive.$internal.com.fasterxml.jackson.core.JsonGenerator;
import com.facebook.presto.hive.$internal.com.fasterxml.jackson.core.JsonParseException;
import com.facebook.presto.hive.$internal.com.fasterxml.jackson.core.JsonParser;
import com.facebook.presto.hive.$internal.com.fasterxml.jackson.databind.JsonNode;
import com.facebook.presto.hive.$internal.com.fasterxml.jackson.databind.ObjectMapper;
import com.facebook.presto.hive.$internal.com.fasterxml.jackson.databind.node.DoubleNode;
import com.facebook.presto.hive.$internal.com.fasterxml.jackson.databind.node.NullNode;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import org.apache.avro.util.internal.Accessor;
import org.apache.avro.util.internal.Accessor.FieldAccessor;
import org.apache.avro.util.internal.JacksonUtils;
import org.apache.avro.util.internal.ThreadLocalWithInitial;
import com.facebook.presto.hive.$internal.org.slf4j.Logger;
import com.facebook.presto.hive.$internal.org.slf4j.LoggerFactory;
import static org.apache.avro.LogicalType.LOGICAL_TYPE_PROP;
/**
* An abstract data type.
*
* A schema may be one of:
*
*
A record, mapping field names to field value data;
*
An enum, containing one of a small set of symbols;
*
An array of values, all of the same schema;
*
A map, containing string/value pairs, of a declared schema;
*
A union of other schemas;
*
A fixed sized binary object;
*
A unicode string;
*
A sequence of bytes;
*
A 32-bit signed int;
*
A 64-bit signed long;
*
A 32-bit IEEE single-float; or
*
A 64-bit IEEE double-float; or
*
A boolean; or
*
null.
*
*
* A schema can be constructed using one of its static createXXX
* methods, or more conveniently using {@link SchemaBuilder}. The schema objects
* are logically immutable. There are only two mutating methods -
* {@link #setFields(List)} and {@link #addProp(String, String)}. The following
* restrictions apply on these two methods.
*
*
{@link #setFields(List)}, can be called at most once. This method exists
* in order to enable clients to build recursive schemas.
*
{@link #addProp(String, String)} can be called with property names that
* are not present already. It is not possible to change or delete an existing
* property.
*
*/
public abstract class Schema extends JsonProperties implements Serializable {
private static final long serialVersionUID = 1L;
protected Object writeReplace() {
SerializableSchema ss = new SerializableSchema();
ss.schemaString = toString();
return ss;
}
private static final class SerializableSchema implements Serializable {
private static final long serialVersionUID = 1L;
private String schemaString;
private Object readResolve() {
return new Schema.Parser().parse(schemaString);
}
}
static final JsonFactory FACTORY = new JsonFactory();
static final Logger LOG = LoggerFactory.getLogger(Schema.class);
static final ObjectMapper MAPPER = new ObjectMapper(FACTORY);
private static final int NO_HASHCODE = Integer.MIN_VALUE;
static {
FACTORY.enable(JsonParser.Feature.ALLOW_COMMENTS);
FACTORY.setCodec(MAPPER);
}
/** The type of a schema. */
public enum Type {
RECORD, ENUM, ARRAY, MAP, UNION, FIXED, STRING, BYTES, INT, LONG, FLOAT, DOUBLE, BOOLEAN, NULL;
private final String name;
private Type() {
this.name = this.name().toLowerCase(Locale.ENGLISH);
}
public String getName() {
return name;
}
};
private final Type type;
private LogicalType logicalType = null;
Schema(Type type) {
super(type == Type.ENUM ? ENUM_RESERVED : SCHEMA_RESERVED);
this.type = type;
}
/** Create a schema for a primitive type. */
public static Schema create(Type type) {
switch (type) {
case STRING:
return new StringSchema();
case BYTES:
return new BytesSchema();
case INT:
return new IntSchema();
case LONG:
return new LongSchema();
case FLOAT:
return new FloatSchema();
case DOUBLE:
return new DoubleSchema();
case BOOLEAN:
return new BooleanSchema();
case NULL:
return new NullSchema();
default:
throw new AvroRuntimeException("Can't create a: " + type);
}
}
private static final Set SCHEMA_RESERVED = new HashSet<>(
Arrays.asList("doc", "fields", "items", "name", "namespace", "size", "symbols", "values", "type", "aliases"));
private static final Set ENUM_RESERVED = new HashSet<>(SCHEMA_RESERVED);
static {
ENUM_RESERVED.add("default");
}
int hashCode = NO_HASHCODE;
@Override
public void addProp(String name, String value) {
super.addProp(name, value);
hashCode = NO_HASHCODE;
}
@Override
public void addProp(String name, Object value) {
super.addProp(name, value);
hashCode = NO_HASHCODE;
}
public LogicalType getLogicalType() {
return logicalType;
}
void setLogicalType(LogicalType logicalType) {
this.logicalType = logicalType;
}
/**
* Create an anonymous record schema.
*
* @deprecated This method allows to create Schema objects that cannot be parsed
* by {@link Schema.Parser#parse(String)}. It will be removed in a
* future version of Avro. Better use
* i{@link #createRecord(String, String, String, boolean, List)} to
* produce a fully qualified Schema.
*/
@Deprecated
public static Schema createRecord(List fields) {
Schema result = createRecord(null, null, null, false);
result.setFields(fields);
return result;
}
/** Create a named record schema. */
public static Schema createRecord(String name, String doc, String namespace, boolean isError) {
return new RecordSchema(new Name(name, namespace), doc, isError);
}
/** Create a named record schema with fields already set. */
public static Schema createRecord(String name, String doc, String namespace, boolean isError, List fields) {
return new RecordSchema(new Name(name, namespace), doc, isError, fields);
}
/** Create an enum schema. */
public static Schema createEnum(String name, String doc, String namespace, List values) {
return new EnumSchema(new Name(name, namespace), doc, new LockableArrayList<>(values), null);
}
/** Create an enum schema. */
public static Schema createEnum(String name, String doc, String namespace, List values, String enumDefault) {
return new EnumSchema(new Name(name, namespace), doc, new LockableArrayList<>(values), enumDefault);
}
/** Create an array schema. */
public static Schema createArray(Schema elementType) {
return new ArraySchema(elementType);
}
/** Create a map schema. */
public static Schema createMap(Schema valueType) {
return new MapSchema(valueType);
}
/** Create a union schema. */
public static Schema createUnion(List types) {
return new UnionSchema(new LockableArrayList<>(types));
}
/** Create a union schema. */
public static Schema createUnion(Schema... types) {
return createUnion(new LockableArrayList<>(types));
}
/** Create a fixed schema. */
public static Schema createFixed(String name, String doc, String space, int size) {
return new FixedSchema(new Name(name, space), doc, size);
}
/** Return the type of this schema. */
public Type getType() {
return type;
}
/**
* If this is a record, returns the Field with the given name
* fieldName. If there is no field by that name, a null is
* returned.
*/
public Field getField(String fieldname) {
throw new AvroRuntimeException("Not a record: " + this);
}
/**
* If this is a record, returns the fields in it. The returned list is in the
* order of their positions.
*/
public List getFields() {
throw new AvroRuntimeException("Not a record: " + this);
}
/**
* If this is a record, returns whether the fields have been set.
*/
public boolean hasFields() {
throw new AvroRuntimeException("Not a record: " + this);
}
/**
* If this is a record, set its fields. The fields can be set only once in a
* schema.
*/
public void setFields(List fields) {
throw new AvroRuntimeException("Not a record: " + this);
}
/** If this is an enum, return its symbols. */
public List getEnumSymbols() {
throw new AvroRuntimeException("Not an enum: " + this);
}
/** If this is an enum, return its default value. */
public String getEnumDefault() {
throw new AvroRuntimeException("Not an enum: " + this);
}
/** If this is an enum, return a symbol's ordinal value. */
public int getEnumOrdinal(String symbol) {
throw new AvroRuntimeException("Not an enum: " + this);
}
/** If this is an enum, returns true if it contains given symbol. */
public boolean hasEnumSymbol(String symbol) {
throw new AvroRuntimeException("Not an enum: " + this);
}
/**
* If this is a record, enum or fixed, returns its name, otherwise the name of
* the primitive type.
*/
public String getName() {
return type.name;
}
/**
* If this is a record, enum, or fixed, returns its docstring, if available.
* Otherwise, returns null.
*/
public String getDoc() {
return null;
}
/** If this is a record, enum or fixed, returns its namespace, if any. */
public String getNamespace() {
throw new AvroRuntimeException("Not a named type: " + this);
}
/**
* If this is a record, enum or fixed, returns its namespace-qualified name,
* otherwise returns the name of the primitive type.
*/
public String getFullName() {
return getName();
}
/** If this is a record, enum or fixed, add an alias. */
public void addAlias(String alias) {
throw new AvroRuntimeException("Not a named type: " + this);
}
/** If this is a record, enum or fixed, add an alias. */
public void addAlias(String alias, String space) {
throw new AvroRuntimeException("Not a named type: " + this);
}
/** If this is a record, enum or fixed, return its aliases, if any. */
public Set getAliases() {
throw new AvroRuntimeException("Not a named type: " + this);
}
/** Returns true if this record is an error type. */
public boolean isError() {
throw new AvroRuntimeException("Not a record: " + this);
}
/** If this is an array, returns its element type. */
public Schema getElementType() {
throw new AvroRuntimeException("Not an array: " + this);
}
/** If this is a map, returns its value type. */
public Schema getValueType() {
throw new AvroRuntimeException("Not a map: " + this);
}
/** If this is a union, returns its types. */
public List getTypes() {
throw new AvroRuntimeException("Not a union: " + this);
}
/** If this is a union, return the branch with the provided full name. */
public Integer getIndexNamed(String name) {
throw new AvroRuntimeException("Not a union: " + this);
}
/** If this is fixed, returns its size. */
public int getFixedSize() {
throw new AvroRuntimeException("Not fixed: " + this);
}
/** Render this as JSON. */
@Override
public String toString() {
return toString(false);
}
/**
* Render this as JSON.
*
* @param pretty if true, pretty-print JSON.
*/
public String toString(boolean pretty) {
return toString(new Names(), pretty);
}
/**
* Render this as JSON, but without inlining the
* referenced schemas.
*
* @param referencedSchemas referenced schemas
* @param pretty if true, pretty-print JSON.
*/
// Use at your own risk. This method should be removed with AVRO-2832.
@Deprecated
public String toString(Collection referencedSchemas, boolean pretty) {
Schema.Names names = new Schema.Names();
if (referencedSchemas != null) {
for (Schema s : referencedSchemas) {
names.add(s);
}
}
return toString(names, pretty);
}
String toString(Names names, boolean pretty) {
try {
StringWriter writer = new StringWriter();
JsonGenerator gen = FACTORY.createGenerator(writer);
if (pretty)
gen.useDefaultPrettyPrinter();
toJson(names, gen);
gen.flush();
return writer.toString();
} catch (IOException e) {
throw new AvroRuntimeException(e);
}
}
void toJson(Names names, JsonGenerator gen) throws IOException {
if (!hasProps()) { // no props defined
gen.writeString(getName()); // just write name
} else {
gen.writeStartObject();
gen.writeStringField("type", getName());
writeProps(gen);
gen.writeEndObject();
}
}
void fieldsToJson(Names names, JsonGenerator gen) throws IOException {
throw new AvroRuntimeException("Not a record: " + this);
}
@Override
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof Schema))
return false;
Schema that = (Schema) o;
if (!(this.type == that.type))
return false;
return equalCachedHash(that) && propsEqual(that);
}
@Override
public final int hashCode() {
if (hashCode == NO_HASHCODE)
hashCode = computeHash();
return hashCode;
}
int computeHash() {
return getType().hashCode() + propsHashCode();
}
final boolean equalCachedHash(Schema other) {
return (hashCode == other.hashCode) || (hashCode == NO_HASHCODE) || (other.hashCode == NO_HASHCODE);
}
private static final Set FIELD_RESERVED = Collections
.unmodifiableSet(new HashSet<>(Arrays.asList("default", "doc", "name", "order", "type", "aliases")));
/** Returns true if this record is an union type. */
public boolean isUnion() {
return this instanceof UnionSchema;
}
/** Returns true if this record is an union type containing null. */
public boolean isNullable() {
if (!isUnion()) {
return getType().equals(Schema.Type.NULL);
}
for (Schema schema : getTypes()) {
if (schema.isNullable()) {
return true;
}
}
return false;
}
/** A field within a record. */
public static class Field extends JsonProperties {
static {
Accessor.setAccessor(new FieldAccessor() {
@Override
protected JsonNode defaultValue(Field field) {
return field.defaultValue();
}
@Override
protected Field createField(String name, Schema schema, String doc, JsonNode defaultValue) {
return new Field(name, schema, doc, defaultValue, true, Order.ASCENDING);
}
@Override
protected Field createField(String name, Schema schema, String doc, JsonNode defaultValue, boolean validate,
Order order) {
return new Field(name, schema, doc, defaultValue, validate, order);
}
});
}
/** How values of this field should be ordered when sorting records. */
public enum Order {
ASCENDING, DESCENDING, IGNORE;
private final String name;
Order() {
this.name = this.name().toLowerCase(Locale.ENGLISH);
}
}
/**
* 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;
private final String doc;
private final JsonNode defaultValue;
private final Order order;
private Set aliases;
Field(String name, Schema schema, String doc, JsonNode defaultValue, boolean validateDefault, Order order) {
super(FIELD_RESERVED);
this.name = validateName(name);
this.schema = Objects.requireNonNull(schema, "schema is required and cannot be null");
this.doc = doc;
this.defaultValue = validateDefault ? validateDefault(name, schema, defaultValue) : defaultValue;
this.order = Objects.requireNonNull(order, "Order cannot be null");
}
/**
* Constructs a new Field instance with the same {@code name}, {@code doc},
* {@code defaultValue}, and {@code order} as {@code field} has with changing
* the schema to the specified one. It also copies all the {@code props} and
* {@code aliases}.
*/
public Field(Field field, Schema schema) {
this(field.name, schema, field.doc, field.defaultValue, 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 == NULL_DEFAULT_VALUE ? NullNode.getInstance() : JacksonUtils.toJsonNode(defaultValue), 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, Order order) {
this(name, schema, doc,
defaultValue == NULL_DEFAULT_VALUE ? NullNode.getInstance() : JacksonUtils.toJsonNode(defaultValue), true,
Objects.requireNonNull(order));
}
public String name() {
return name;
};
/** The position of this field within the record. */
public int pos() {
return position;
}
/** This field's {@link Schema}. */
public Schema schema() {
return schema;
}
/** Field's documentation within the record, if set. May return null. */
public String doc() {
return doc;
}
/**
* @return true if this Field has a default value set. Can be used to determine
* if a "null" return from defaultVal() is due to that being the default
* value or just not set.
*/
public boolean hasDefaultValue() {
return defaultValue != null;
}
JsonNode defaultValue() {
return defaultValue;
}
/**
* @return the default value for this field specified using the mapping in
* {@link JsonProperties}
*/
public Object defaultVal() {
return JacksonUtils.toObject(defaultValue, schema);
}
public Order order() {
return order;
}
public void addAlias(String alias) {
if (aliases == null)
this.aliases = new LinkedHashSet<>();
aliases.add(alias);
}
/** Return the defined aliases as an unmodifiable Set. */
public Set aliases() {
if (aliases == null)
return Collections.emptySet();
return Collections.unmodifiableSet(aliases);
}
@Override
public boolean equals(Object other) {
if (other == this)
return true;
if (!(other instanceof Field))
return false;
Field that = (Field) other;
return (name.equals(that.name)) && (schema.equals(that.schema)) && defaultValueEquals(that.defaultValue)
&& (order == that.order) && propsEqual(that);
}
@Override
public int hashCode() {
return name.hashCode() + schema.computeHash();
}
private boolean defaultValueEquals(JsonNode thatDefaultValue) {
if (defaultValue == null)
return thatDefaultValue == null;
if (thatDefaultValue == null)
return false;
if (Double.isNaN(defaultValue.doubleValue()))
return Double.isNaN(thatDefaultValue.doubleValue());
return defaultValue.equals(thatDefaultValue);
}
@Override
public String toString() {
return name + " type:" + schema.type + " pos:" + position;
}
}
static class Name {
private final String name;
private final String space;
private final String full;
public Name(String name, String space) {
if (name == null) { // anonymous
this.name = this.space = this.full = null;
return;
}
int lastDot = name.lastIndexOf('.');
if (lastDot < 0) { // unqualified name
this.name = validateName(name);
} else { // qualified name
space = name.substring(0, lastDot); // get space from name
this.name = validateName(name.substring(lastDot + 1));
}
if ("".equals(space))
space = null;
this.space = space;
this.full = (this.space == null) ? this.name : this.space + "." + this.name;
}
@Override
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof Name))
return false;
Name that = (Name) o;
return Objects.equals(full, that.full);
}
@Override
public int hashCode() {
return full == null ? 0 : full.hashCode();
}
@Override
public String toString() {
return full;
}
public void writeName(Names names, JsonGenerator gen) throws IOException {
if (name != null)
gen.writeStringField("name", name);
if (space != null) {
if (!space.equals(names.space()))
gen.writeStringField("namespace", space);
} else if (names.space() != null) { // null within non-null
gen.writeStringField("namespace", "");
}
}
public String getQualified(String defaultSpace) {
return this.shouldWriteFull(defaultSpace) ? full : name;
}
/**
* Determine if full name must be written. There are 2 cases for true :
* defaultSpace != from this.space or name is already a Schema.Type (int, array
* ...)
*
* @param defaultSpace : default name space.
* @return true if full name must be written.
*/
private boolean shouldWriteFull(String defaultSpace) {
if (space != null && space.equals(defaultSpace)) {
for (Type schemaType : Type.values()) {
if (schemaType.name.equals(name)) {
// name is a 'Type', so namespace must be written
return true;
}
}
// this.space == defaultSpace
return false;
}
// this.space != defaultSpace, so namespace must be written.
return true;
}
}
private static abstract class NamedSchema extends Schema {
final Name name;
final String doc;
Set aliases;
public NamedSchema(Type type, Name name, String doc) {
super(type);
this.name = name;
this.doc = doc;
if (PRIMITIVES.containsKey(name.full)) {
throw new AvroTypeException("Schemas may not be named after primitives: " + name.full);
}
}
@Override
public String getName() {
return name.name;
}
@Override
public String getDoc() {
return doc;
}
@Override
public String getNamespace() {
return name.space;
}
@Override
public String getFullName() {
return name.full;
}
@Override
public void addAlias(String alias) {
addAlias(alias, null);
}
@Override
public void addAlias(String name, String space) {
if (aliases == null)
this.aliases = new LinkedHashSet<>();
if (space == null)
space = this.name.space;
aliases.add(new Name(name, space));
}
@Override
public Set getAliases() {
Set result = new LinkedHashSet<>();
if (aliases != null)
for (Name alias : aliases)
result.add(alias.full);
return result;
}
public boolean writeNameRef(Names names, JsonGenerator gen) throws IOException {
if (this.equals(names.get(name))) {
gen.writeString(name.getQualified(names.space()));
return true;
} else if (name.name != null) {
names.put(name, this);
}
return false;
}
public void writeName(Names names, JsonGenerator gen) throws IOException {
name.writeName(names, gen);
}
public boolean equalNames(NamedSchema that) {
return this.name.equals(that.name);
}
@Override
int computeHash() {
return super.computeHash() + name.hashCode();
}
public void aliasesToJson(JsonGenerator gen) throws IOException {
if (aliases == null || aliases.isEmpty())
return;
gen.writeFieldName("aliases");
gen.writeStartArray();
for (Name alias : aliases)
gen.writeString(alias.getQualified(name.space));
gen.writeEndArray();
}
}
/**
* Useful as key of {@link Map}s when traversing two schemas at the same time
* and need to watch for recursion.
*/
public static class SeenPair {
private Object s1;
private Object s2;
public SeenPair(Object s1, Object s2) {
this.s1 = s1;
this.s2 = s2;
}
public boolean equals(Object o) {
if (!(o instanceof SeenPair))
return false;
return this.s1 == ((SeenPair) o).s1 && this.s2 == ((SeenPair) o).s2;
}
@Override
public int hashCode() {
return System.identityHashCode(s1) + System.identityHashCode(s2);
}
}
private static final ThreadLocal SEEN_EQUALS = ThreadLocalWithInitial.of(HashSet::new);
private static final ThreadLocal