Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nullable fields from schema are not reflected in generated C# #169

Closed
ievgenii-shepeliuk opened this issue Jan 19, 2022 · 8 comments · Fixed by #184
Closed

Nullable fields from schema are not reflected in generated C# #169

ievgenii-shepeliuk opened this issue Jan 19, 2022 · 8 comments · Fixed by #184
Labels
bug Something isn't working enhancement New feature or request
Milestone

Comments

@ievgenii-shepeliuk
Copy link

ievgenii-shepeliuk commented Jan 19, 2022

Hello

I'm using dotnet avro generate to create C# class from Avro schema.

My schema looks like

{
  "name": "Models.MyClass",
  "type": "record",
  "fields": [
    {"name": "BoolField", "type": ["null", "boolean"]},
    {"name": "StringField", "type": ["null", "string"]},
    {
      "name": "RecordField",
      "type": ["null", {
        "name": "Models.Credentials",
        "type": "record",
        "fields": [
          {"name": "Password", "type": "string"},
          {"name": "Username", "type": "string"}
        ]
      }]
    }, {
      "name": "EnumField",
      "type": ["null", {
        "name": "Models.AccountStatus",
        "type": "enum",
        "symbols": ["New", "Active"]
      }]
    }
  ]
}

I expect that properties BoolField, StringField, RecordField, EnumField will be nullable in generated class. But they are not.
The resulting C# class looks like

namespace Models
{
    public enum AccountStatus
    {
        New,
        Active
    }

    public class Credentials
    {
        public string Password { get; set; }
        public string Username { get; set; }
    }

    public class MyClass
    {
        public bool? BoolField { get; set; }
        public string StringField { get; set; }
        public Credentials RecordField { get; set; }
        public AccountStatus EnumField { get; set; }
    }
}

Am I missing smth or this is a bug in code generation ?

@dstelljes
Copy link
Member

At the moment, code generation only supports nullable value types (note the bool? above), not reference types. We plan to fully support nullable reference types in 8.x.

That said, enums are value types and thus should be supported currently; #171 fixes that bug and will be included in the next 7.2.x.

@dstelljes dstelljes added bug Something isn't working enhancement New feature or request labels Jan 19, 2022
@dstelljes dstelljes added this to the 8.0.0 milestone Jan 19, 2022
@ievgenii-shepeliuk
Copy link
Author

Looking forward new release, thanks for fixing it.

@ievgenii-shepeliuk
Copy link
Author

@dstelljes is it possible to somehow hack it on serialization level, so even if fields is not nullable in C# class - when value of reference type is null - it will be serialized as null ?

@dstelljes
Copy link
Member

Yes, that’s how Chr.Avro currently behaves—the library is oblivious to C# 8+ nullable reference types.

@ievgenii-shepeliuk
Copy link
Author

Can you provide an example ? I have an exception when serializing messages.

Although I have more complicated setup - i am wrapping Chr.Avro serializer to use it together with https://github.com/Farfetch/kafka-flow

I am creating an instance

_serializer = new AsyncSchemaRegistrySerializer<T>(schemaRegistryClient);

and then invoke SerializeAsync()

@dstelljes
Copy link
Member

Sure, say I’m using your schema:

{
  "name": "Models.MyClass",
  "type": "record",
  "fields": [
    {
      "name": "RecordField",
      "type": ["null", {
        "name": "Models.Credentials",
        "type": "record",
        "fields": [
          {"name": "Password", "type": "string"},
          {"name": "Username", "type": "string"}
        ]
      }]
    }
  ]
}

and mapping it to these classes:

#nullable disable // turn off nullable reference types to match Chr.Avro

namespace Models
{
    public class Credentials
    {
        public string Password { get; set; }
        public string Username { get; set; }
    }

    public class MyClass
    {
        public Credentials RecordField { get; set; }
    }
}

the serializer would allow me to do this:

var context = new SerializationContext(MessageComponentType.Value, "example-topic");

// this should work because `RecordField` is `["null", ...]`
await _serializer.SerializeAsync(new MyClass { RecordField = null }, context);

but not this:

var context = new SerializationContext(MessageComponentType.Value, "example-topic");

// this would not work because `Password` is not `["null", ...]`
await _serializer.SerializeAsync(new MyClass { RecordField = new Credentials { Username = "user", Password = null } }, context);

@ievgenii-shepeliuk
Copy link
Author

Yes, worked. Thanks for your help !

@dstelljes dstelljes linked a pull request Feb 10, 2022 that will close this issue
@dstelljes
Copy link
Member

Full nullable reference type support is released with 8.0.0-pre.1.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants