use of com.linkedin.avroutil1.model.AvroType in project avro-util by linkedin.
the class AvscParser method parseComplexSchema.
private SchemaOrRef parseComplexSchema(JsonObjectExt objectNode, AvscFileParseContext context, boolean topLevel) {
CodeLocation codeLocation = locationOf(context.getUri(), objectNode);
Located<String> typeStr = getRequiredString(objectNode, "type", () -> "it is a schema declaration");
AvroType avroType = AvroType.fromTypeName(typeStr.getValue());
if (avroType == null) {
throw new AvroSyntaxException("unknown avro type \"" + typeStr.getValue() + "\" at " + typeStr.getLocation() + ". expecting \"record\", \"enum\" or \"fixed\"");
}
LinkedHashMap<String, JsonValueExt> propsMap = parseExtraProps(objectNode, CORE_SCHEMA_PROPERTIES);
JsonPropertiesContainer props = propsMap.isEmpty() ? JsonPropertiesContainer.EMPTY : new JsonPropertiesContainerImpl(propsMap);
AvroSchema definedSchema;
if (avroType.isNamed()) {
definedSchema = parseNamedSchema(objectNode, context, avroType, codeLocation, props);
} else if (avroType.isCollection()) {
definedSchema = parseCollectionSchema(objectNode, context, avroType, codeLocation, props);
} else if (avroType.isPrimitive()) {
definedSchema = parseDecoratedPrimitiveSchema(objectNode, context, avroType, codeLocation, props);
} else {
throw new IllegalStateException("unhandled avro type " + avroType + " at " + typeStr.getLocation());
}
context.defineSchema(definedSchema, topLevel);
return new SchemaOrRef(codeLocation, definedSchema);
}
use of com.linkedin.avroutil1.model.AvroType in project avro-util by linkedin.
the class AvscParser method parseDecoratedPrimitiveSchema.
private AvroPrimitiveSchema parseDecoratedPrimitiveSchema(JsonObjectExt primitiveNode, AvscFileParseContext context, AvroType avroType, CodeLocation codeLocation, JsonPropertiesContainer props) {
AvroLogicalType logicalType = null;
int scale = 0;
int precision = 0;
Parsed<AvroLogicalType> logicalTypeResult = parseLogicalType(primitiveNode, context, avroType, codeLocation);
if (logicalTypeResult.hasIssues()) {
context.addIssues(logicalTypeResult.getIssues());
}
// might be null
logicalType = logicalTypeResult.getData();
Parsed<AvroJavaStringRepresentation> stringRepResult = parseStringRepresentation(primitiveNode, context, avroType, codeLocation);
AvroJavaStringRepresentation stringRep = null;
if (stringRepResult.hasIssues()) {
context.addIssues(stringRepResult.getIssues());
}
if (AvroType.STRING.equals(avroType) && stringRepResult.hasData()) {
stringRep = stringRepResult.getData();
}
Located<Integer> precisionResult = getOptionalInteger(primitiveNode, "precision", context);
Located<Integer> scaleResult = getOptionalInteger(primitiveNode, "scale", context);
boolean scaleAndPrecisionExpected = AvroType.BYTES.equals(avroType) && AvroLogicalType.DECIMAL.equals(logicalType);
if (scaleAndPrecisionExpected) {
boolean scaleAndPrecisionOK = true;
int precisionValue = 0;
int scaleValue = 0;
// precision is actually required
if (precisionResult == null) {
context.addIssue(AvscIssues.precisionRequiredAndNotSet(codeLocation, avroType, logicalType));
scaleAndPrecisionOK = false;
}
if (scaleAndPrecisionOK && scaleResult != null) {
precisionValue = precisionResult.getValue();
scaleValue = scaleResult.getValue();
if (precisionValue < scaleValue) {
context.addIssue(AvscIssues.precisionSmallerThanScale(locationOf(context.getUri(), precisionResult), precisionValue, locationOf(context.getUri(), scaleResult), scaleValue));
scaleAndPrecisionOK = false;
}
}
if (scaleAndPrecisionOK) {
scale = scaleValue;
precision = precisionValue;
} else {
// "cancel" the logicalType
logicalType = null;
}
}
return new AvroPrimitiveSchema(codeLocation, avroType, logicalType, stringRep, scale, precision, props);
}
use of com.linkedin.avroutil1.model.AvroType in project avro-util by linkedin.
the class AvscParser method parseNamedSchema.
private AvroNamedSchema parseNamedSchema(JsonObjectExt objectNode, AvscFileParseContext context, AvroType avroType, CodeLocation codeLocation, JsonPropertiesContainer extraProps) {
AvroName schemaName = parseSchemaName(objectNode, context, avroType);
List<AvroName> aliases = parseAliases(objectNode, context, avroType, schemaName);
// technically the avro spec does not allow "doc" on type fixed, but screw that
Located<String> docStr = getOptionalString(objectNode, "doc");
String doc = docStr != null ? docStr.getValue() : null;
boolean namespaceChanged = false;
// check if context namespace changed
if (!context.getCurrentNamespace().equals(schemaName.getNamespace())) {
context.pushNamespace(schemaName.getNamespace());
namespaceChanged = true;
}
AvroNamedSchema namedSchema;
switch(avroType) {
case RECORD:
AvroRecordSchema recordSchema = new AvroRecordSchema(codeLocation, schemaName, aliases, doc, extraProps);
JsonArrayExt fieldsNode = getRequiredArray(objectNode, "fields", () -> "all avro records must have fields");
List<AvroSchemaField> fields = new ArrayList<>(fieldsNode.size());
for (int fieldNum = 0; fieldNum < fieldsNode.size(); fieldNum++) {
// !=null
JsonValueExt fieldDeclNode = (JsonValueExt) fieldsNode.get(fieldNum);
JsonValue.ValueType fieldNodeType = fieldDeclNode.getValueType();
if (fieldNodeType != JsonValue.ValueType.OBJECT) {
throw new AvroSyntaxException("field " + fieldNum + " for record " + schemaName.getSimpleName() + " at " + fieldDeclNode.getStartLocation() + " expected to be an OBJECT, not a " + JsonPUtil.describe(fieldNodeType) + " (" + fieldDeclNode + ")");
}
TextLocation fieldStartLocation = Util.convertLocation(fieldDeclNode.getStartLocation());
TextLocation fieldEndLocation = Util.convertLocation(fieldDeclNode.getEndLocation());
CodeLocation fieldCodeLocation = new CodeLocation(context.getUri(), fieldStartLocation, fieldEndLocation);
JsonObjectExt fieldDecl = (JsonObjectExt) fieldDeclNode;
Located<String> fieldName = getRequiredString(fieldDecl, "name", () -> "all record fields must have a name");
JsonValueExt fieldTypeNode = getRequiredNode(fieldDecl, "type", () -> "all record fields must have a type");
Located<String> locatedDocField = getOptionalString(fieldDecl, "doc");
String docField = locatedDocField == null ? null : locatedDocField.getValue();
SchemaOrRef fieldSchema = parseSchemaDeclOrRef(fieldTypeNode, context, false);
JsonValueExt fieldDefaultValueNode = fieldDecl.get("default");
AvroLiteral defaultValue = null;
if (fieldDefaultValueNode != null) {
if (fieldSchema.isResolved()) {
LiteralOrIssue defaultValurOrIssue = parseLiteral(fieldDefaultValueNode, fieldSchema.getSchema(), fieldName.getValue(), context);
if (defaultValurOrIssue.getIssue() == null) {
defaultValue = defaultValurOrIssue.getLiteral();
}
// TODO - handle issues
} else {
// TODO - implement delayed default value parsing
throw new UnsupportedOperationException("delayed parsing of default value for " + fieldName.getValue() + " TBD");
}
}
LinkedHashMap<String, JsonValueExt> props = parseExtraProps(fieldDecl, CORE_FIELD_PROPERTIES);
JsonPropertiesContainer propsContainer = props.isEmpty() ? JsonPropertiesContainer.EMPTY : new JsonPropertiesContainerImpl(props);
AvroSchemaField field = new AvroSchemaField(fieldCodeLocation, fieldName.getValue(), docField, fieldSchema, defaultValue, propsContainer);
fields.add(field);
}
recordSchema.setFields(fields);
namedSchema = recordSchema;
break;
case ENUM:
JsonArrayExt symbolsNode = getRequiredArray(objectNode, "symbols", () -> "all avro enums must have symbols");
List<String> symbols = new ArrayList<>(symbolsNode.size());
for (int ordinal = 0; ordinal < symbolsNode.size(); ordinal++) {
JsonValueExt symbolNode = (JsonValueExt) symbolsNode.get(ordinal);
JsonValue.ValueType symbolNodeType = symbolNode.getValueType();
if (symbolNodeType != JsonValue.ValueType.STRING) {
throw new AvroSyntaxException("symbol " + ordinal + " for enum " + schemaName.getSimpleName() + " at " + symbolNode.getStartLocation() + " expected to be a STRING, not a " + JsonPUtil.describe(symbolNodeType) + " (" + symbolNode + ")");
}
symbols.add(symbolNode.toString());
}
String defaultSymbol = null;
Located<String> defaultStr = getOptionalString(objectNode, "default");
if (defaultStr != null) {
defaultSymbol = defaultStr.getValue();
if (!symbols.contains(defaultSymbol)) {
context.addIssue(AvscIssues.badEnumDefaultValue(locationOf(context.getUri(), defaultStr), defaultSymbol, schemaName.getSimpleName(), symbols));
// TODO - support "fixing" by selecting 1st symbol as default?
defaultSymbol = null;
}
}
namedSchema = new AvroEnumSchema(codeLocation, schemaName, aliases, doc, symbols, defaultSymbol, extraProps);
break;
case FIXED:
JsonValueExt sizeNode = getRequiredNode(objectNode, "size", () -> "fixed types must have a size property");
if (sizeNode.getValueType() != JsonValue.ValueType.NUMBER || !(((JsonNumberExt) sizeNode).isIntegral())) {
throw new AvroSyntaxException("size for fixed " + schemaName.getSimpleName() + " at " + sizeNode.getStartLocation() + " expected to be an INTEGER, not a " + JsonPUtil.describe(sizeNode.getValueType()) + " (" + sizeNode + ")");
}
int fixedSize = ((JsonNumberExt) sizeNode).intValue();
Parsed<AvroLogicalType> logicalTypeResult = parseLogicalType(objectNode, context, avroType, codeLocation);
if (logicalTypeResult.hasIssues()) {
context.addIssues(logicalTypeResult.getIssues());
}
namedSchema = new AvroFixedSchema(codeLocation, schemaName, aliases, doc, fixedSize, logicalTypeResult.getData(), extraProps);
break;
default:
throw new IllegalStateException("unhandled: " + avroType + " for object at " + codeLocation.getStart());
}
if (namespaceChanged) {
context.popNamespace();
}
return namedSchema;
}
use of com.linkedin.avroutil1.model.AvroType in project avro-util by linkedin.
the class AvscSchemaWriter method writeNamedSchema.
protected JsonValue writeNamedSchema(AvroNamedSchema schema, AvscWriterContext context, AvscWriterConfig config) {
boolean seenBefore = context.schemaEncountered(schema);
if (seenBefore) {
return writeSchemaRef(schema, context, config);
}
// common parts to all named schemas
JsonObjectBuilder definitionBuilder = Json.createObjectBuilder();
AvroName extraAlias = emitSchemaName(schema, context, config, definitionBuilder);
emitSchemaAliases(schema, context, config, extraAlias, definitionBuilder);
if (schema.getDoc() != null) {
definitionBuilder.add("doc", Json.createValue(schema.getDoc()));
}
AvroType type = schema.type();
switch(type) {
case ENUM:
AvroEnumSchema enumSchema = (AvroEnumSchema) schema;
definitionBuilder.add("type", "enum");
List<String> symbols = enumSchema.getSymbols();
JsonArrayBuilder arrayBuilder = Json.createArrayBuilder();
for (String symbol : symbols) {
arrayBuilder.add(symbol);
}
definitionBuilder.add("symbols", arrayBuilder);
String defaultSymbol = enumSchema.getDefaultSymbol();
if (defaultSymbol != null) {
definitionBuilder.add("default", Json.createValue(defaultSymbol));
}
break;
case FIXED:
AvroFixedSchema fixedSchema = (AvroFixedSchema) schema;
definitionBuilder.add("type", "fixed");
definitionBuilder.add("size", Json.createValue(fixedSchema.getSize()));
break;
case RECORD:
AvroRecordSchema recordSchema = (AvroRecordSchema) schema;
// TODO - support error types?
definitionBuilder.add("type", "record");
emitRecordFields(recordSchema, context, config, definitionBuilder);
break;
default:
throw new IllegalStateException("not expecting " + type);
}
emitJsonProperties(schema, context, config, definitionBuilder);
context.popNamingContext();
return definitionBuilder.build();
}
use of com.linkedin.avroutil1.model.AvroType in project avro-util by linkedin.
the class AvscSchemaWriter method writeSchema.
protected JsonValue writeSchema(AvroSchema schema, AvscWriterContext context, AvscWriterConfig config) {
AvroType type = schema.type();
JsonObjectBuilder definitionBuilder;
switch(type) {
case ENUM:
case FIXED:
case RECORD:
return writeNamedSchema((AvroNamedSchema) schema, context, config);
case ARRAY:
AvroArraySchema arraySchema = (AvroArraySchema) schema;
definitionBuilder = Json.createObjectBuilder();
definitionBuilder.add("type", "array");
definitionBuilder.add("items", writeSchema(arraySchema.getValueSchema(), context, config));
emitJsonProperties(schema, context, config, definitionBuilder);
return definitionBuilder.build();
case MAP:
AvroMapSchema mapSchema = (AvroMapSchema) schema;
definitionBuilder = Json.createObjectBuilder();
definitionBuilder.add("type", "map");
definitionBuilder.add("values", writeSchema(mapSchema.getValueSchema(), context, config));
emitJsonProperties(schema, context, config, definitionBuilder);
return definitionBuilder.build();
case UNION:
AvroUnionSchema unionSchema = (AvroUnionSchema) schema;
JsonArrayBuilder unionBuilder = Json.createArrayBuilder();
for (SchemaOrRef unionBranch : unionSchema.getTypes()) {
// will throw if unresolved ref
AvroSchema branchSchema = unionBranch.getSchema();
unionBuilder.add(writeSchema(branchSchema, context, config));
}
return unionBuilder.build();
default:
AvroPrimitiveSchema primitiveSchema = (AvroPrimitiveSchema) schema;
if (!primitiveSchema.hasProperties()) {
return Json.createValue(primitiveSchema.type().name().toLowerCase(Locale.ROOT));
}
definitionBuilder = Json.createObjectBuilder();
definitionBuilder.add("type", primitiveSchema.type().toTypeName());
emitJsonProperties(primitiveSchema, context, config, definitionBuilder);
return definitionBuilder.build();
}
}
Aggregations