如何将可选的类列表定义为 Avro Schema 中的字段之一以避免 Avro 序列化错误?

问题描述 投票:0回答:1

我的要求是将数据存储在数据库中:如果

addresses
是通过邮递员按要求发送的,那么不应发送
currentAddress
previousAddresses
,如果两者都已发送,则不应发送
addresses
完全发送。

Addresses, PreviousAddresses 和 CurrentAddress 定义为:

private List<MyClassOldAddress> addresses;
private List<MyClassAddress> previousAddresses;
private MyClassAddress currentAddress;

我做了什么: 我已经定义了一个 Avro-Schema(使用 v1.11.1),如下所示,它被转换成 Java 类,供 API 使用,我们发送请求正文将数据存储在数据库中。

{
   "namespace":"com.avro.data",
   "type":"record",
   "name":"MyClass",
   "fields":[
      {
         "name":"userId",
         "type":"string",
         "docs":"This is the unique id for user."
      },
      {
         "name":"middleName",
         "type":[
            "null",
            "string"
         ],
         "avro.java.string":"String"
      },
      {
         "name":"firstName",
         "type":"string",
         "avro.java.string":"String"
      },
      {
         "name":"lastName",
         "type":"string",
         "avro.java.string":"String"
      },
      {
         "name":"addresses",
         "type":{
            "type":"array",
            "items":"com.data.MyClassAddress"
         },
         "default": []
      },
      {
         "name":"previousAddresses",
         "type":{
            "type":"array",
            "items":"com.data.MyClassOtherAddress"
         },
         "default": []
      },
      {
      "name": "currentAddress",
      "type": [
            "null",
            "com.data.MyClassOtherAddress"
            ],
      "default": null
    }
   ]
}

当我通过 Postman 的请求并按照如下要求将字段

addresses
currentAddress 
previousAddresses
发送为 null 或空 [] 时,它会抛出一些错误:

请求 1:

{
   "userId":"123",
   "middle_name":"user_middle_name",
   "first_name":"user_first_name",
   "last_name":"user_last_name",
   "addresses":[
      {
         "street_name":"testing",
         "town":"testing",
         "country":"ABC",
         "postcode":"123456",
         "house_number":"123",
         "start_date":"2000-01"
      }
   ],
   "previous_addresses":[],
   "current_address":null
}

请求 2:

{
   "userId":"123",
   "middle_name":"user_middle_name",
   "first_name":"user_first_name",
   "last_name":"user_last_name",
   "addresses":[],
   "previous_addresses":[...some data here...],
   "current_address":{...some data here...}
}

错误:

Caused by: java.lang.NullPointerException: null value for (non-nullable) List\<MyClassAddress\> at

Caused by: org.apache.kafka.common.errors.SerializationException: Error serializing Avro message

我的观察: 通过识别,我开始知道如果任何字段(

addresses
currentAddress
previousAddresses
)作为null或[]发送,则在将其存储到数据库之前无法序列化。

但是当我在这些对象中放入任何东西时,它不会失败。但是我做不到,我必须按要求设置。

那么,我该如何避免这种情况,将 Avro-Schema 中的所有 3 个字段都设为可选字段,以便在序列化时不会产生任何问题?

我尝试添加“default:[]”、“default: null”、“null”,但都没有用!请帮助。

我尝试在某些条件下发送请求(发送地址时,不应发送 currentAddress 和 previousAddresses,反之亦然)但序列化失败。

我希望它能在没有序列化错误的情况下工作,如果字段丢失(根据要求),它不应该失败。

java spring-boot gradle avro
1个回答
1
投票

Avro 要求严格的模式兼容性,这意味着用于序列化数据的模式必须与用于反序列化数据的模式完全相同。 例如,当请求正文(您尝试通过 Postman 发送)中缺少您的可选字段时,反序列化器将无法将缺少的字段与模式中的字段匹配,从而导致 Avro 模式序列化错误。

我建议您对 IF 条件进行空检查,并为可选字段/类的每个字段创建一个空/空构造函数,以避免在反序列化时丢失 avro 模式中的字段。这样你就不会在该特定类的可选字段中传递任何值,另一方面,满足模式字段,以便反序列化程序检查并满足于根据定义的模式没有遗漏任何东西。

© www.soinside.com 2019 - 2024. All rights reserved.