[ 
https://issues.apache.org/jira/browse/AVRO-4054?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17880793#comment-17880793
 ] 

Rob Komjathy commented on AVRO-4054:
------------------------------------

Yeah I was trying not to have to extend a 3rd party library for my own purpose, 
just philosophically it adds a complication whenever we need to get the latest 
from Apache, in case the underlying APIs change.  Ideally the original objects 
behave as expected and we as users don't need to dive into 3rd party 
implementation to discover that under the hood, dictionaries need to be 
<string, object>.

I have a test class going that extends DefaultWriter and will see if this works 
for my purposes.  I ended up also needing to override Matches, btw.  The Map 
case also wanted the cast to <string, object> in DefaultWriter.
{code:java}
protected override bool Matches(Schema sc, object obj)
{
    if (obj == null && sc.Tag != Schema.Type.Null)
        return false;
    switch (sc.Tag)
    {
        case Schema.Type.Null:
            return obj == null;
        case Schema.Type.Boolean:
            return obj is bool;
        case Schema.Type.Int:
            return obj is int;
        case Schema.Type.Long:
            return obj is long;
        case Schema.Type.Float:
            return obj is float;
        case Schema.Type.Double:
            return obj is double;
        case Schema.Type.Bytes:
            return obj is byte[];
        case Schema.Type.String:
            return obj is string;
        case Schema.Type.Record:
            return obj is GenericRecord && (obj as 
GenericRecord).Schema.SchemaName.Equals((object)(sc as 
RecordSchema).SchemaName);
        case Schema.Type.Enumeration:
            return obj is GenericEnum && (obj as 
GenericEnum).Schema.SchemaName.Equals((object)(sc as EnumSchema).SchemaName);
        case Schema.Type.Array:
            return obj is Array && !(obj is byte[]);
        case Schema.Type.Map:
            return obj is IDictionary;
        case Schema.Type.Union:
            return false;
        case Schema.Type.Fixed:
            return obj is GenericFixed && (obj as 
GenericFixed).Schema.SchemaName.Equals((object)(sc as FixedSchema).SchemaName);
        case Schema.Type.Logical:
            return (sc as 
LogicalSchema).LogicalType.IsInstanceOfLogicalType(obj);
        default:
            throw new AvroException("Unknown schema type: " + 
sc.Tag.ToString());
    }
} {code}
Thanks [[email protected]] for your suggestions here.

> Serialization of C# Dictionary only works if type is <string, object>
> ---------------------------------------------------------------------
>
>                 Key: AVRO-4054
>                 URL: https://issues.apache.org/jira/browse/AVRO-4054
>             Project: Apache Avro
>          Issue Type: Bug
>          Components: csharp
>    Affects Versions: 1.12.0
>         Environment: I was testing this in a .Net Standard 2.0 project.
>            Reporter: Rob Komjathy
>            Priority: Major
>
> I encountered an unexpected behavior with Avro Maps (C# Dictionaries).  If I 
> directly try to serialize a Dictionary<string, T> where T is any type besides 
> literally "object", an exception is thrown. 
> If you dig into the code, it's because you can't directly cast 
> Dictionary<string, T> to Dictionary<string, object>.  This fails on at least 
> 3 lines in DefaultWriter, as there are several attempts made to verify the 
> Dictionary "is" <string, object> or can be cast to it directly.
> For example, here is a rudimentary example.
>  
> {code:java}
> var schema = MapSchema.CreateMap(PrimitiveSchema.Create(Schema.Type.Long));
> var ms = new MemoryStream();
> Encoder enc = new BinaryEncoder(ms);
> var writer = new DefaultWriter(schema);
> writer.Write(new Dictionary<string, long>(), enc);
> enc.Flush(); {code}
> Given this example, I would expect to be able to pass a Dictionary<string, 
> long> given the schema I have defined.  Instead this throws an exception. 
>  
> The work around is to create a new Dictionary<string, object> and 
> individually cast the values to "objects".  For example:
>  
> {code:java}
> public static Dictionary<string, object> ToAvroSafeDictionary<TValue>(this 
> IDictionary<string, TValue> dictionary)
> {
>     return dictionary?.ToDictionary(k => k.Key, v => (object)v.Value);
> } {code}
> I originally encountered this with my own custom schema but as you can see, 
> using Apache Avro's own schema objects in the rudimentary example exhibit the 
> same issue.
>  



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to