Uploaded image for project: 'Apache Avro'
  1. Apache Avro
  2. AVRO-3786

[Rust] Deserialization results in FindUnionVariant error if the writer and reader have the same symbol but at different positions

    XMLWordPrintableJSON

Details

    Description

      When calling from_avro_datum with a reader schema that has the same enum symbol but in a different position as the writer schema, a FindUnionVariant error occurs. The value in the message is available in both schemas. The enum is defined elsewhere in the schema, so it's worth checking if the problem is with the reference type or the enum itself.

       

      Sample test

      #[test]
          fn deserialize_union_with_different_enum_order() -> TestResult {
              #[derive(Debug, PartialEq, Eq, Clone, serde::Deserialize, serde::Serialize)]
              pub struct BarUseParent {
                  #[serde(rename = "barUse")]
                  pub bar_use: Bar,
              }
      
              #[derive(Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Clone, serde::Deserialize, serde::Serialize)]
              pub enum Bar {
                  #[serde(rename = "bar0")]
                  Bar0,
                  #[serde(rename = "bar1")]
                  Bar1,
                  #[serde(rename = "bar2")]
                  Bar2,
              }
      
              #[derive(Debug, PartialEq, Eq, Clone, serde::Deserialize, serde::Serialize)]
              pub struct Foo {
                  #[serde(rename = "barInit")]
                  pub bar_init: Bar,
                  #[serde(rename = "barUseParent")]
                  pub bar_use_parent: Option<BarUseParent>,
              }
      
              let writer_schema = r#"{
                  "type": "record",
                  "name": "Foo",
                  "fields":
                  [
                      {
                          "name": "barInit",
                          "type":
                          {
                              "type": "enum",
                              "name": "Bar",
                              "symbols":
                              [
                                  "bar0",
                                  "bar1",
                                  "bar2"
                              ],
                              "default": "bar0"
                          }
                      },
                      {
                          "name": "barUseParent",
                          "type": [
                              "null",
                              {
                                  "type": "record",
                                  "name": "BarUseParent",
                                  "fields": [
                                      {
                                          "name": "barUse",
                                          "type": "Bar"
                                      }
                                  ]
                              }
                          ]
                      }
                  ]
              }"#;
      
              let reader_schema = r#"{
                  "type": "record",
                  "name": "Foo",
                  "fields":
                  [
                      {
                          "name": "barInit",
                          "type":
                          {
                              "type": "enum",
                              "name": "Bar",
                              "symbols":
                              [
                                  "bar1"
                              ],
                              "default": "bar1"
                          }
                      },
                      {
                          "name": "barUseParent",
                          "type": [
                              "null",
                              {
                                  "type": "record",
                                  "name": "BarUseParent",
                                  "fields": [
                                      {
                                          "name": "barUse",
                                          "type": "Bar"
                                      }
                                  ]
                              }
                          ]
                      }
                  ]
                  }"#;
      
              let writer_schema = Schema::parse_str(writer_schema)?;
              let foo = Foo {
                  bar_init: Bar::Bar1,
                  bar_use_parent: Some(BarUseParent { bar_use: Bar::Bar1} ),
              };
              let avro_value = crate::to_value(foo)?;
              assert!(
                  avro_value.validate(&writer_schema),
                  "value is valid for schema",
              );
              let datum = crate::to_avro_datum(&writer_schema, avro_value)?;
              let mut x = &datum[..];
              let reader_schema = Schema::parse_str(reader_schema)?;
              let deser_value = crate::from_avro_datum(&writer_schema, &mut x, Some(&reader_schema))?;
              match deser_value {
                  types::Value::Record(fields) => {
                      assert_eq!(fields.len(), 2);
                      assert_eq!(fields[0].0, "barInit");
                      assert_eq!(fields[0].1, types::Value::Enum(1, "bar1".to_string()));
                      assert_eq!(fields[1].0, "barUseParent");
                      // TODO: assert barUseParent value
                  }
                  _ => panic!("Expected Value::Record"),
              }        Ok(())
          }         Ok(())    } 

      Resulting error:

      apache_avro::error::Error: Could not find matching type in union 

      Attachments

        Issue Links

          Activity

            People

              mgrigorov Martin Tzvetanov Grigorov
              evanmb27 Evan Blackwell
              Votes:
              0 Vote for this issue
              Watchers:
              4 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:

                Time Tracking

                  Estimated:
                  Original Estimate - Not Specified
                  Not Specified
                  Remaining:
                  Remaining Estimate - 0h
                  0h
                  Logged:
                  Time Spent - 20m
                  20m