Search in sources :

Example 1 with UnionDataSchema

use of com.linkedin.data.schema.UnionDataSchema in project rest.li by linkedin.

the class SchemaToAvroJsonEncoder method encodeFieldType.

/**
   * Encode a field's type to an Avro-compliant schema.
   *
   * Special handling is required for optional fields.
   * An optional field is encoded as a union with null.
   * If the optional field is not a union, then union
   * the field's type with null.
   * If the optional field is already a union, then
   * include null as a member type if it is not already
   * part of the union.
   * If the resulting type is a union and resulting field
   * has a default value, then the resulting union's list
   * of member types are encoded such that the type of
   * the translated default value is always the 1st type
   * in this list (see Avro specification for more details.)
   *
   * For required and non-union fields, no special handling is required.
   *
   * @param field providing the type to encode.
   * @throws IOException if there is an error while encoding.
   */
@Override
protected void encodeFieldType(RecordDataSchema.Field field) throws IOException {
    boolean optional = field.getOptional();
    DataSchema fieldSchema = field.getType();
    UnionDataSchema unionDataSchema = (fieldSchema.getDereferencedType() == DataSchema.Type.UNION ? (UnionDataSchema) fieldSchema.getDereferencedDataSchema() : null);
    _builder.writeFieldName(TYPE_KEY);
    if (optional == false && unionDataSchema == null) {
        encode(fieldSchema);
    } else {
        // special handling for unions
        // output will be an union if the field is optional or its type is a union
        // whether to add null to translated union,
        // set to true for optional non-union type or optional union without null member
        boolean addNullMemberType;
        // DataSchema of default value, null if there is no default value.
        DataSchema defaultValueSchema;
        // members of the union (excluding null introduced by optional)
        List<DataSchema> resultMemberTypes;
        Object defaultValue = field.getDefault();
        if (optional) {
            if (unionDataSchema == null) {
                addNullMemberType = true;
                resultMemberTypes = new ArrayList<DataSchema>(1);
                resultMemberTypes.add(fieldSchema);
                defaultValueSchema = (defaultValue != null && _options.getOptionalDefaultMode() == OptionalDefaultMode.TRANSLATE_DEFAULT ? fieldSchema : DataSchemaConstants.NULL_DATA_SCHEMA);
            } else {
                addNullMemberType = unionDataSchema.getType(DataSchemaConstants.NULL_TYPE) == null;
                resultMemberTypes = unionDataSchema.getTypes();
                defaultValueSchema = (defaultValue != null && _options.getOptionalDefaultMode() == OptionalDefaultMode.TRANSLATE_DEFAULT ? unionValueDataSchema(unionDataSchema, defaultValue) : DataSchemaConstants.NULL_DATA_SCHEMA);
            }
            assert (_options.getOptionalDefaultMode() != OptionalDefaultMode.TRANSLATE_TO_NULL || defaultValueSchema == DataSchemaConstants.NULL_DATA_SCHEMA);
        } else {
            // must be union
            addNullMemberType = false;
            resultMemberTypes = unionDataSchema.getTypes();
            defaultValueSchema = unionValueDataSchema(unionDataSchema, defaultValue);
        }
        // encode the member types
        // add null member type if addNullMemberType is present
        _builder.writeStartArray();
        // this variable keeps track of whether null member type has been emitted
        boolean emittedNull = false;
        // if field has a default, defaultValueSchema != null, always encode it 1st
        if (defaultValueSchema != null) {
            emittedNull |= (defaultValueSchema.getDereferencedType() == DataSchema.Type.NULL);
            encode(defaultValueSchema);
        }
        for (DataSchema type : resultMemberTypes) {
            if (defaultValueSchema == type) {
                continue;
            }
            if (type.getDereferencedType() == DataSchema.Type.NULL) {
                if (emittedNull)
                    continue;
                else
                    emittedNull = true;
            }
            encode(type);
        }
        // emit null member type if it is has to be added and has not already been emitted
        if (addNullMemberType && emittedNull == false) {
            _builder.writeString(DataSchemaConstants.NULL_TYPE);
            emittedNull = true;
        }
        assert (addNullMemberType == false || emittedNull == true);
        _builder.writeEndArray();
    }
}
Also used : DataSchema(com.linkedin.data.schema.DataSchema) RecordDataSchema(com.linkedin.data.schema.RecordDataSchema) UnionDataSchema(com.linkedin.data.schema.UnionDataSchema) UnionDataSchema(com.linkedin.data.schema.UnionDataSchema)

Example 2 with UnionDataSchema

use of com.linkedin.data.schema.UnionDataSchema in project rest.li by linkedin.

the class DataElementUtil method element.

/**
   * Get the {@link DataElement} by following the specified path starting from
   * the provided {@link DataElement}.
   *
   * @param element provides the {@link DataElement} that is the starting point.
   * @param path provides the path components through an {@link Iterable}.
   * @return the {@link DataElement} if the path can be followed, else return null.
   * @throws IllegalArgumentException if the provided path's syntax is incorrect, Data object does not match provided
   *                                  {@link DataSchema}.
   */
public static DataElement element(DataElement element, Iterable<Object> path) throws IllegalArgumentException {
    DataElement currentElement = element;
    for (Object component : path) {
        Object name;
        if (currentElement.getValue().getClass() == DataMap.class && component.getClass() != String.class) {
            name = component.toString();
        } else if (currentElement.getValue().getClass() == DataList.class && component.getClass() != Integer.class) {
            try {
                name = Integer.parseInt(component.toString());
            } catch (NumberFormatException e) {
                return null;
            }
        } else {
            name = component;
        }
        Object childValue = currentElement.getChild(name);
        if (childValue == null) {
            return null;
        }
        DataSchema childSchema = null;
        DataSchema schema = currentElement.getSchema();
        if (schema != null) {
            schema = schema.getDereferencedDataSchema();
            switch(schema.getType()) {
                case ARRAY:
                    childSchema = ((ArrayDataSchema) schema).getItems();
                    break;
                case MAP:
                    childSchema = ((MapDataSchema) schema).getValues();
                    break;
                case UNION:
                    childSchema = ((UnionDataSchema) schema).getType((String) name);
                    break;
                case RECORD:
                    RecordDataSchema.Field field = ((RecordDataSchema) schema).getField((String) name);
                    if (field != null) {
                        childSchema = field.getType();
                    }
                    break;
                default:
                    throw new IllegalArgumentException(currentElement.pathAsString() + " has schema of type " + schema.getType() + " which cannot have child, but has child with name \"" + name + "\"");
            }
        }
        currentElement = new SimpleDataElement(childValue, name, childSchema, currentElement);
    }
    return currentElement;
}
Also used : RecordDataSchema(com.linkedin.data.schema.RecordDataSchema) DataSchema(com.linkedin.data.schema.DataSchema) UnionDataSchema(com.linkedin.data.schema.UnionDataSchema) MapDataSchema(com.linkedin.data.schema.MapDataSchema) ArrayDataSchema(com.linkedin.data.schema.ArrayDataSchema) RecordDataSchema(com.linkedin.data.schema.RecordDataSchema) DataMap(com.linkedin.data.DataMap)

Example 3 with UnionDataSchema

use of com.linkedin.data.schema.UnionDataSchema in project rest.li by linkedin.

the class TestSchemaSampleDataGenerator method testUnionSchema.

@Test
public void testUnionSchema() {
    final UnionDataSchema schema = (UnionDataSchema) DataTemplateUtil.getSchema(UnionTest.UnionWithNull.class);
    final Set<String> memberKeys = new HashSet<String>();
    for (DataSchema memberSchema : schema.getTypes()) {
        memberKeys.add(memberSchema.getUnionMemberKey());
    }
    final String nullMemberKey = DataSchemaConstants.NULL_DATA_SCHEMA.getUnionMemberKey();
    for (int i = 0; i < memberKeys.size() * 2; ++i) {
        final DataMap value = (DataMap) SchemaSampleDataGenerator.buildData(schema, _spec);
        if (value == null) {
            Assert.assertTrue(memberKeys.contains(nullMemberKey));
            continue;
        }
        final String key = value.keySet().iterator().next();
        Assert.assertTrue(memberKeys.contains(key));
    }
}
Also used : UnionDataSchema(com.linkedin.data.schema.UnionDataSchema) PrimitiveDataSchema(com.linkedin.data.schema.PrimitiveDataSchema) EnumDataSchema(com.linkedin.data.schema.EnumDataSchema) TyperefDataSchema(com.linkedin.data.schema.TyperefDataSchema) RecordDataSchema(com.linkedin.data.schema.RecordDataSchema) ArrayDataSchema(com.linkedin.data.schema.ArrayDataSchema) FixedDataSchema(com.linkedin.data.schema.FixedDataSchema) DataSchema(com.linkedin.data.schema.DataSchema) MapDataSchema(com.linkedin.data.schema.MapDataSchema) UnionDataSchema(com.linkedin.data.schema.UnionDataSchema) ByteString(com.linkedin.data.ByteString) HashSet(java.util.HashSet) DataMap(com.linkedin.data.DataMap) UnionTest(com.linkedin.pegasus.generator.test.UnionTest) Test(org.testng.annotations.Test) TyperefTest(com.linkedin.pegasus.generator.test.TyperefTest)

Example 4 with UnionDataSchema

use of com.linkedin.data.schema.UnionDataSchema in project rest.li by linkedin.

the class TemplateSpecGenerator method generateUnion.

private UnionTemplateSpec generateUnion(UnionDataSchema schema, UnionTemplateSpec unionClass) {
    final Map<CustomInfoSpec, Object> customInfoMap = new IdentityHashMap<CustomInfoSpec, Object>(schema.getTypes().size() * 2);
    for (DataSchema memberType : schema.getTypes()) {
        final UnionTemplateSpec.Member newMember = new UnionTemplateSpec.Member();
        unionClass.getMembers().add(newMember);
        newMember.setSchema(memberType);
        if (memberType.getDereferencedType() != DataSchema.Type.NULL) {
            newMember.setClassTemplateSpec(processSchema(memberType, unionClass, memberType.getUnionMemberKey()));
            newMember.setDataClass(determineDataClass(memberType, unionClass, memberType.getUnionMemberKey()));
            final CustomInfoSpec customInfo = getImmediateCustomInfo(memberType);
            if (customInfo != null) {
                if (!customInfoMap.containsKey(customInfo)) {
                    customInfoMap.put(customInfo, null);
                }
                newMember.setCustomInfo(customInfo);
            }
        }
    }
    return unionClass;
}
Also used : FixedDataSchema(com.linkedin.data.schema.FixedDataSchema) DataSchema(com.linkedin.data.schema.DataSchema) UnionDataSchema(com.linkedin.data.schema.UnionDataSchema) MapDataSchema(com.linkedin.data.schema.MapDataSchema) ComplexDataSchema(com.linkedin.data.schema.ComplexDataSchema) PrimitiveDataSchema(com.linkedin.data.schema.PrimitiveDataSchema) EnumDataSchema(com.linkedin.data.schema.EnumDataSchema) TyperefDataSchema(com.linkedin.data.schema.TyperefDataSchema) RecordDataSchema(com.linkedin.data.schema.RecordDataSchema) NamedDataSchema(com.linkedin.data.schema.NamedDataSchema) ArrayDataSchema(com.linkedin.data.schema.ArrayDataSchema) CustomInfoSpec(com.linkedin.pegasus.generator.spec.CustomInfoSpec) IdentityHashMap(java.util.IdentityHashMap) UnionTemplateSpec(com.linkedin.pegasus.generator.spec.UnionTemplateSpec)

Example 5 with UnionDataSchema

use of com.linkedin.data.schema.UnionDataSchema in project rest.li by linkedin.

the class TemplateSpecGenerator method processSchema.

private ClassTemplateSpec processSchema(DataSchema schema, ClassTemplateSpec enclosingClass, String memberName) {
    final CustomInfoSpec customInfo = getImmediateCustomInfo(schema);
    ClassTemplateSpec result = null;
    TyperefDataSchema originalTyperefSchema = null;
    while (schema.getType() == DataSchema.Type.TYPEREF) {
        final TyperefDataSchema typerefSchema = (TyperefDataSchema) schema;
        if (originalTyperefSchema == null) {
            originalTyperefSchema = typerefSchema;
        }
        final ClassTemplateSpec found = _schemaToClassMap.get(schema);
        schema = typerefSchema.getRef();
        if (found == null) {
            if (schema.getType() == DataSchema.Type.UNION) {
                result = generateUnion((UnionDataSchema) schema, typerefSchema);
                break;
            } else {
                generateTyperef(typerefSchema, originalTyperefSchema);
            }
        } else if (schema.getType() == DataSchema.Type.UNION) {
            result = found;
            break;
        }
    }
    if (result == null) {
        assert schema == schema.getDereferencedDataSchema();
        if (schema instanceof ComplexDataSchema) {
            final ClassTemplateSpec found = _schemaToClassMap.get(schema);
            if (found == null) {
                if (schema instanceof NamedDataSchema) {
                    result = generateNamedSchema((NamedDataSchema) schema);
                } else {
                    result = generateUnnamedComplexSchema(schema, enclosingClass, memberName);
                }
            } else {
                result = found;
            }
            if (customInfo != null) {
                result = customInfo.getCustomClass();
            }
        } else if (schema instanceof PrimitiveDataSchema) {
            result = (customInfo != null) ? customInfo.getCustomClass() : getPrimitiveClassForSchema((PrimitiveDataSchema) schema, enclosingClass, memberName);
        }
    }
    if (result == null) {
        throw unrecognizedSchemaType(enclosingClass, memberName, schema);
    }
    result.setOriginalTyperefSchema(originalTyperefSchema);
    return result;
}
Also used : NamedDataSchema(com.linkedin.data.schema.NamedDataSchema) UnionDataSchema(com.linkedin.data.schema.UnionDataSchema) PrimitiveDataSchema(com.linkedin.data.schema.PrimitiveDataSchema) ClassTemplateSpec(com.linkedin.pegasus.generator.spec.ClassTemplateSpec) TyperefDataSchema(com.linkedin.data.schema.TyperefDataSchema) CustomInfoSpec(com.linkedin.pegasus.generator.spec.CustomInfoSpec) ComplexDataSchema(com.linkedin.data.schema.ComplexDataSchema)

Aggregations

UnionDataSchema (com.linkedin.data.schema.UnionDataSchema)14 DataSchema (com.linkedin.data.schema.DataSchema)11 RecordDataSchema (com.linkedin.data.schema.RecordDataSchema)11 TyperefDataSchema (com.linkedin.data.schema.TyperefDataSchema)11 ArrayDataSchema (com.linkedin.data.schema.ArrayDataSchema)10 MapDataSchema (com.linkedin.data.schema.MapDataSchema)10 EnumDataSchema (com.linkedin.data.schema.EnumDataSchema)7 FixedDataSchema (com.linkedin.data.schema.FixedDataSchema)7 NamedDataSchema (com.linkedin.data.schema.NamedDataSchema)7 PrimitiveDataSchema (com.linkedin.data.schema.PrimitiveDataSchema)6 DataMap (com.linkedin.data.DataMap)5 DataList (com.linkedin.data.DataList)2 ComplexDataSchema (com.linkedin.data.schema.ComplexDataSchema)2 CustomInfoSpec (com.linkedin.pegasus.generator.spec.CustomInfoSpec)2 UnionTemplateSpec (com.linkedin.pegasus.generator.spec.UnionTemplateSpec)2 ArrayList (java.util.ArrayList)2 HashSet (java.util.HashSet)2 Test (org.testng.annotations.Test)2 ByteString (com.linkedin.data.ByteString)1 TypeAssignmentContext (com.linkedin.data.grammar.PdlParser.TypeAssignmentContext)1