为什么原来是字符串的 Avro 字段现在需要 avro.java.string 类型?

Why does an Avro field that was string now require avro.java.string type?

在 Avro IDL 中,我有一条消息记录定义如下:

record Message{

    MessageId id;
    array<string> dataField;
}

我在另一个具有空联合的记录中使用此记录:

record Invoice{
    ...
    union {null,array<Message>} message;
}

我们有一个 Java Kafka 消费者(我们正在使用 Confluent Platform),它使用 avro-maven-plugin 版本 1.10.2,配置 <stringType>String</stringType>

当我们进行这样的调用时:

List<String> msgList = message.getDataField();
for (String msg : msgList) {...}

我们在第二行收到以下错误:class org.apache.avro.util.Utf8 cannot be cast to class java.lang.String

之前,Invoice 对象被定义为:

 record Invoice{
    ...
    array<Message> message;
}

我们没有收到这个错误。我们发现在我们的模式文件中,从

 "name" : "dataField",
      "type" : {
        "type" : "array",
        "items" : "string"
      }

"name" : "dataField",
 "type" : {
   "type" : "array",
     "items" :{
        "type": "string",
        "avro.java.string" : "String"
   }
 }

修正问题。

我不清楚为什么添加联合会导致这种行为变化。我是否应该使用 avro.java.string 声明架构中的所有字符串,如果是这样,我该如何使用 Avro IDL 来实现?

此时,似乎有几种方法可以解决此问题,至少在使用 Confluent Platform 5.5.1 或更高版本时是这样。我正在考虑问题是 Avro 的 open defect

第一个选项是通过全局搜索更新 Avro 架构文件并将 "type":"string" 替换为

"type": {
       "avro.java.string": "String",
       "type": "string"
    }

第一个选项需要在通过 Avro IDL 创建任何文件后完成,因为它不支持此构造,使得 IDL 在这种情况下不太有用。奇怪的是,这种方法似乎不会影响通过 REST 代理进入的记录,这些记录具有 "type":"string" 关联但没有额外的 avro.java.string 信息。他们似乎能够使用以任何一种方式定义的模式;我原以为包含 avro.java.string 信息的更新架构会导致没有该详细信息的 REST 代理请求出现问题。

第二个选项是设置 auto.register.schemas=falseuse.latest.version=true,尽管这可能会在未来的兼容性方面造成意想不到的后果。

第三个选项是不在 Avro 工具的 Maven 配置中使用 <stringType> 指令。这意味着围绕默认使用的 CharacterSequence 进行大量编码,通常以 .toString() 方法的形式。