使用avro4k向Azure服务总线发送GenericRecord时触发类型异常
解决avro4k ListRecord发送至Azure服务总线时的"Not a named type: int"异常
问题重现
发送avro4k生成的GenericRecord(ListRecord)到Azure服务总线时,抛出以下异常:
com.digitalchargingsolutions.middleware.servicebus.client.exception.ServiceBusClientException: Not a named type: "int" (through reference chain: com.github.avrokotlin.avro4k.ListRecord["s"]->org.apache.avro.Schema$RecordSchema["fields"]->org.apache.avro.Schema$LockableArrayList[0]->org.apache.avro.Schema$Field["schema"]->org.apache.avro.Schema$IntSchema["aliases"])
对应的实体类:
@Serializable data class User1( val id: Int, val name: String )
调用代码:
val user = User1(1, "User") val avroData = Avro.default.toRecord(User1.serializer(), user) sender2.sendMessage(avroData).getOrThrow()
注:直接发送ByteArray时功能正常,尝试@AvroAlias注解无法解决问题。
原因分析
- Azure服务总线Schema要求:服务总线的Avro客户端期望Schema中的所有类型均为命名类型(带有明确名称/命名空间标识),但avro4k默认生成的基本类型(如int、string)为匿名Schema,无显式名称标识,导致解析失败。
- GenericRecord实现差异:avro4k生成的
ListRecord是自定义的GenericRecord实现,在Schema属性(如aliases)的处理逻辑上与Apache Avro原生的GenericData.Record存在差异,客户端遍历Schema链时触发异常。
解决方案
方案1:转换为Apache原生GenericData.Record
将avro4k生成的ListRecord转换为Apache Avro原生的GenericData.Record,确保客户端能正确解析Schema:
val user = User1(1, "User") val avroSchema = Avro.default.schema(User1.serializer()) val avroListRecord = Avro.default.toRecord(User1.serializer(), user) // 转换为原生GenericData.Record val genericRecord = GenericData.Record(avroSchema).apply { avroSchema.fields.forEach { field -> put(field.name(), avroListRecord.get(field.name())) } } sender2.sendMessage(genericRecord).getOrThrow()
方案2:直接发送序列化后的ByteArray
既然该方式原本功能正常,可继续使用此方式规避Schema解析问题:
val user = User1(1, "User") val byteArray = Avro.default.encodeToByteArray(User1.serializer(), user) sender2.sendMessage(byteArray).getOrThrow()
方案3:为实体类添加命名空间
通过@AvroNamespace注解为实体类指定命名空间,让生成的Schema带有明确标识,帮助客户端识别类型:
@Serializable @AvroNamespace("com.your.project.namespace") data class User1( val id: Int, val name: String )
内容的提问来源于stack exchange,提问作者Nemanja Andjelkovic
相关产品推荐
相关产品推荐

