Search code examples
c#schemaavro

Unable to assign arrays in Avro Genericrecord. getting error - Cannot find a match for System.Collections.Generic.List`1


My Avro schema is -

{Schema: {"type":"record","name":"Header","namespace":"EMployee.schema","fields":[{"name":"changeTypes","default":null,"type":["null",{"type":"array","items":["null","string"]}]},{"name":"correlationId","default":null,"type":["null","string"]},{"name":"entityId","default":null,"type":["null","string"]},{"name":"entityType","default":null,"type":["null","string"]},{"name":"eventTimestamp","default":null,"type":["null","string"]},{"name":"eventType","default":null,"type":["null","string"]},{"name":"originalEventType","default":null,"type":["null","string"]},{"name":"originalSourceSystem","default":null,"type":["null","string"]},{"name":"sourceId","default":null,"type":["null","string"]},{"name":"sourceSystem","default":null,"type":["null","string"]}]},

contents: { changeTypes: System.Collections.Generic.List`1[System.String], correlationId: c4f6c7fb001546c5ad436376a502ff31, entityId: 1, entityType: Employee, eventTimestamp: 4/14/2024 4:19:45 PM, eventType: createEmployee, originalEventType: Create, originalSourceSystem: Workday, sourceId: 2, sourceSystem: Workday, }}

If we inspect the schema contents, the value of changeType is System.Collections.Generic.List1[System.String]. I am using the method below to assign values to the GenericRecord` object. However, when I post it to the Redpanda topic, it throws an error.

Cannot find a match for System.Collections.Generic.List`1[System.String] in ["null",{"type":"array","items":["null","string"]}] in field changeTypes in field header.

my code is -

   static object ConvertToAvroCompatibleType(Avro.Schema schema, object value)
        {
            if (schema is Avro.UnionSchema unionSchema)
            {
                var actualSchema = unionSchema.Schemas.FirstOrDefault(s => s.Tag != Avro.Schema.Type.Null);

                if (actualSchema == null)
                {
                    return null;
                }
                return ConvertToAvroCompatibleType(actualSchema, value);
            }
            else
            {
                switch (schema.Tag)
                {
                    case Avro.Schema.Type.String:
                        return value?.ToString();

                    case Avro.Schema.Type.Int:
                        return value is int ? (int)value : 0;

                    case Avro.Schema.Type.Array:
                        var arraySchema = (ArraySchema)schema;
                        var avroArray = new List<string>(); 

                        if (value is IEnumerable enumerable)
                        {
                            foreach (var item in enumerable)
                            {
                                avroArray.Add(item?.ToString());
                            }
                            return avroArray;
                        }
                        else
                        {
                            return null;
                        }
                    default:
                        return null;
                }
            }
        }

Can anyone help me with how I should pass an array into a GenericRecord? Or could you advise on what the issue might be in this context?

   static object ConvertToAvroCompatibleType(Avro.Schema schema, object value)
        {
            if (schema is Avro.UnionSchema unionSchema)
            {
                var actualSchema = unionSchema.Schemas.FirstOrDefault(s => s.Tag != Avro.Schema.Type.Null);

                if (actualSchema == null)
                {
                    return null;
                }
                return ConvertToAvroCompatibleType(actualSchema, value);
            }
            else
            {
                switch (schema.Tag)
                {
                    case Avro.Schema.Type.String:
                        return value?.ToString();

                    case Avro.Schema.Type.Int:
                        return value is int ? (int)value : 0;

                    case Avro.Schema.Type.Array:
                        var arraySchema = (ArraySchema)schema;
                        var avroArray = new List<string>(); 

                        if (value is IEnumerable enumerable)
                        {
                            foreach (var item in enumerable)
                            {
                                avroArray.Add(item?.ToString());
                            }
                            return avroArray;
                        }
                        else
                        {
                            return null;
                        }
                    default:
                        return null;
                }
            }
        }

Solution

  • I resolved this issue:- instead of returning 'return avroArray' I used 'return avroArray.ToArray()'. and it's working.