Avro4k字段设null为默认值时的Schema生成问题及解决方法
解决avro4k生成Avro Schema时的两个规范问题
在使用avro4k定义可空BigDecimal字段时,生成的Schema存在两个不符合Avro规范的问题:
- 默认值
null被添加了引号,不符合规范要求的字面量null - 包含
null的union类型中,null排在了decimal类型之后,违反了"默认值需匹配union第一个类型"的规范
原定义代码
@Serializable data class Product( @AvroDefault("null") @ScalePrecision(DEFAULT_SCALE, DEFAULT_PRECISION) @Serializable(with = BigDecimalSerializer::class) val price: BigDecimal? = null )
生成的问题Schema
{ "type" : "record", "name" : "Product", "namespace" : "org.company", "fields" : [ { "name" : "ask", "type" : [ { "type" : "bytes", "logicalType" : "decimal", "precision" : 7, "scale" : 2 }, "null" ], "default" : "null" } ] }
问题1:默认值null带引号的修复
将@AvroDefault("null")替换为@AvroDefault(AvroNull)。avro4k提供了AvroNull常量,专门用于表示Avro规范中的字面量null,替换后生成的default值会是无引号的null。
问题2:union类型中null排首位的修复
avro4k默认会将非null类型放在union的第一位,可通过两种方式调整顺序:
方式1:字段级注解指定union顺序
直接在字段上用@AvroSchema定义符合要求的union结构:
@Serializable data class Product( @AvroDefault(AvroNull) @ScalePrecision(DEFAULT_SCALE, DEFAULT_PRECISION) @Serializable(with = BigDecimalSerializer::class) @AvroSchema("[\"null\", {\"type\": \"bytes\", \"logicalType\": \"decimal\", \"precision\": 7, \"scale\": 2}]") val price: BigDecimal? = null )
方式2:全局配置Schema生成策略
如果需要统一处理所有可空类型的union顺序,可在生成Schema时配置AvroConfiguration,设置unionOrder为UnionOrder.NULL_FIRST:
val schema = Avro.default.open(Product.serializer()) .configure(AvroConfiguration(unionOrder = UnionOrder.NULL_FIRST)) .schema()
修改后的正确Schema示例
{ "type" : "record", "name" : "Product", "namespace" : "org.company", "fields" : [ { "name" : "price", "type" : [ "null", { "type" : "bytes", "logicalType" : "decimal", "precision" : 7, "scale" : 2 } ], "default" : null } ] }
内容的提问来源于stack exchange,提问作者AmsterdamLuis
相关产品推荐
相关产品推荐

