首页 > 解决方案 > 为什么字符串的 Avro 字段现在需要 avro.java.string 类型?

问题描述

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

record Message{

    MessageId id;
    array<string> dataField;
}

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

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

我们有一个使用 1.10.2 版本的 Java Kafka 消费者(我们正在使用 Confluent 平台)avro-maven-plugin,配置为<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 来做到这一点?

标签: javaavroconfluent-platformavro-tools

解决方案


在这一点上,似乎有几种方法可以解决这个问题,至少在使用 Confluent Platform 5.5.1 或更高版本时是这样。我认为这个问题是 Avro 的一个公开缺陷

第一个选项是使用全局搜索更新 Avro Schema 文件并将其替换"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=falseand use.latest.version=true,尽管这可能会在将来导致与兼容性有关的意外后果。

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


推荐阅读