Search in sources :

Example 6 with AvroType

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);
}
Also used : CodeLocation(com.linkedin.avroutil1.model.CodeLocation) AvroSchema(com.linkedin.avroutil1.model.AvroSchema) SchemaOrRef(com.linkedin.avroutil1.model.SchemaOrRef) AvroType(com.linkedin.avroutil1.model.AvroType) AvroSyntaxException(com.linkedin.avroutil1.parser.exceptions.AvroSyntaxException) JsonPropertiesContainer(com.linkedin.avroutil1.model.JsonPropertiesContainer) JsonValueExt(com.linkedin.avroutil1.parser.jsonpext.JsonValueExt)

Example 7 with AvroType

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);
}
Also used : BigInteger(java.math.BigInteger) AvroPrimitiveSchema(com.linkedin.avroutil1.model.AvroPrimitiveSchema) AvroLogicalType(com.linkedin.avroutil1.model.AvroLogicalType) AvroJavaStringRepresentation(com.linkedin.avroutil1.model.AvroJavaStringRepresentation)

Example 8 with AvroType

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;
}
Also used : AvroSyntaxException(com.linkedin.avroutil1.parser.exceptions.AvroSyntaxException) ArrayList(java.util.ArrayList) JsonPropertiesContainer(com.linkedin.avroutil1.model.JsonPropertiesContainer) AvroNamedSchema(com.linkedin.avroutil1.model.AvroNamedSchema) JsonArrayExt(com.linkedin.avroutil1.parser.jsonpext.JsonArrayExt) AvroEnumSchema(com.linkedin.avroutil1.model.AvroEnumSchema) AvroFixedSchema(com.linkedin.avroutil1.model.AvroFixedSchema) AvroLiteral(com.linkedin.avroutil1.model.AvroLiteral) JsonNumberExt(com.linkedin.avroutil1.parser.jsonpext.JsonNumberExt) CodeLocation(com.linkedin.avroutil1.model.CodeLocation) SchemaOrRef(com.linkedin.avroutil1.model.SchemaOrRef) AvroName(com.linkedin.avroutil1.model.AvroName) JsonValue(javax.json.JsonValue) AvroRecordSchema(com.linkedin.avroutil1.model.AvroRecordSchema) AvroLogicalType(com.linkedin.avroutil1.model.AvroLogicalType) JsonObjectExt(com.linkedin.avroutil1.parser.jsonpext.JsonObjectExt) JsonValueExt(com.linkedin.avroutil1.parser.jsonpext.JsonValueExt) TextLocation(com.linkedin.avroutil1.model.TextLocation) AvroSchemaField(com.linkedin.avroutil1.model.AvroSchemaField)

Example 9 with AvroType

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();
}
Also used : AvroEnumSchema(com.linkedin.avroutil1.model.AvroEnumSchema) AvroType(com.linkedin.avroutil1.model.AvroType) AvroName(com.linkedin.avroutil1.model.AvroName) JsonArrayBuilder(javax.json.JsonArrayBuilder) AvroFixedSchema(com.linkedin.avroutil1.model.AvroFixedSchema) AvroRecordSchema(com.linkedin.avroutil1.model.AvroRecordSchema) JsonObjectBuilder(javax.json.JsonObjectBuilder)

Example 10 with AvroType

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();
    }
}
Also used : AvroArraySchema(com.linkedin.avroutil1.model.AvroArraySchema) AvroPrimitiveSchema(com.linkedin.avroutil1.model.AvroPrimitiveSchema) SchemaOrRef(com.linkedin.avroutil1.model.SchemaOrRef) AvroSchema(com.linkedin.avroutil1.model.AvroSchema) AvroType(com.linkedin.avroutil1.model.AvroType) AvroMapSchema(com.linkedin.avroutil1.model.AvroMapSchema) AvroUnionSchema(com.linkedin.avroutil1.model.AvroUnionSchema) JsonArrayBuilder(javax.json.JsonArrayBuilder) JsonObjectBuilder(javax.json.JsonObjectBuilder)

Aggregations

AvroType (com.linkedin.avroutil1.model.AvroType)8 SchemaOrRef (com.linkedin.avroutil1.model.SchemaOrRef)7 CodeLocation (com.linkedin.avroutil1.model.CodeLocation)6 AvroArraySchema (com.linkedin.avroutil1.model.AvroArraySchema)5 AvroSyntaxException (com.linkedin.avroutil1.parser.exceptions.AvroSyntaxException)5 JsonValueExt (com.linkedin.avroutil1.parser.jsonpext.JsonValueExt)5 AvroName (com.linkedin.avroutil1.model.AvroName)4 AvroPrimitiveSchema (com.linkedin.avroutil1.model.AvroPrimitiveSchema)4 AvroEnumSchema (com.linkedin.avroutil1.model.AvroEnumSchema)3 AvroFixedSchema (com.linkedin.avroutil1.model.AvroFixedSchema)3 AvroLiteral (com.linkedin.avroutil1.model.AvroLiteral)3 AvroLogicalType (com.linkedin.avroutil1.model.AvroLogicalType)3 AvroMapSchema (com.linkedin.avroutil1.model.AvroMapSchema)3 AvroRecordSchema (com.linkedin.avroutil1.model.AvroRecordSchema)3 AvroSchema (com.linkedin.avroutil1.model.AvroSchema)3 JsonArrayExt (com.linkedin.avroutil1.parser.jsonpext.JsonArrayExt)3 ArrayList (java.util.ArrayList)3 JsonArrayBuilder (javax.json.JsonArrayBuilder)3 JsonValue (javax.json.JsonValue)3 AvroArrayLiteral (com.linkedin.avroutil1.model.AvroArrayLiteral)2