Skip to content
New issue

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

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

Already on GitHub? # to your account

Fail to deserialize generated unions #73

Open
oringnes opened this issue Sep 25, 2024 · 2 comments
Open

Fail to deserialize generated unions #73

oringnes opened this issue Sep 25, 2024 · 2 comments

Comments

@oringnes
Copy link

Hi,

When working with a union of records, I am unable to deserialize record using apache_avro.
Example schema Foo.avsc:

{
  "type": "record",
  "name": "Foo",
  "fields": [
    {"name": "a", "type": "int"},
    {"name": "b",
      "type":
      [
        {
          "type": "record",
          "name": "Bar",
          "fields": [
            {"name": "c", "type": "long"}
          ]
        },
        {
          "type": "record",
          "name": "Baz",
          "fields": [
            {"name": "d", "type": "int"}
          ]
        }
      ]
    }
  ]
}

Expecting struct to be identical when serialized, and then deserialized:

    #[test]
    fn test_foo_serde() {
        let before = Foo {
            a: 0,
            b: UnionBarBaz::Baz(Baz {
                d: 42,
            })
        };

        let schema = Schema::parse_str(include_str!("../avsc/Foo.avsc")).unwrap();

        let mut writer = Writer::new(&schema, Vec::new());
        writer.append_ser(before.clone()).unwrap();
        let encoded = writer.into_inner().unwrap();

        let mut reader = Reader::with_schema(&schema, &encoded[..]).unwrap();
        let value = reader.next().unwrap();
        let after: Foo = from_value::<Foo>(&value.unwrap()).unwrap();

        assert_eq!(before, after);
    }

The call to from_value() is responding with the following error:

Failed to deserialize Avro value into value: Expected a Record|Enum, but got Union(1, Record([("d", Int(42))]))

@lerouxrgd
Copy link
Owner

Hi,

This is actually a tricky one. The root of this problem stems from the mismatch between the "Union variant" that gets serialized and the "Record value" that is expected by the deserializer.

Handling this for basic types (ints, floats, etc) isn't too hard and is already implemented, it is available with the flag --union-deser. However for potentially recursive types, such as a record, I haven't found a good solution yet as things can get pretty nasty to template/generate. In the code right now, when using --union-deser GenUnionVisitor::serde_visitor will be set to None, which, when templated, will be discarded.

Any help on this topic is welcomed.

@lerouxrgd
Copy link
Owner

It might also be possible to handle this issue directly in apache_avro, I would to look into it.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants