You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

dataclasses-avroschema中联合类型序列化反序列化结果不符问题

问题:dataclasses-avroschema联合类型反序列化后类型不匹配

使用dataclasses-avroschema对包含联合类型的数据类进行序列化/反序列化时,反序列化得到的对象类型与原对象不符。原对象是MessageTypeTwo,反序列化后变成了MessageTypeOne。

代码重现

from dataclasses_avroschema import AvroModel
from dataclasses import dataclass
import typing

@dataclass
class MessageTypeTwo(AvroModel):
    val: typing.Union[None, str]
    class Meta:
        namespace = "Messages.type.two"

@dataclass
class MessageTypeOne(AvroModel):
    class Meta:
        namespace = "Messages.type.one"

@dataclass
class CoreMessage(AvroModel):
    messageBody: typing.Union[
        MessageTypeOne,
        MessageTypeTwo,
    ]

# 序列化反序列化操作
mt2 = MessageTypeTwo(val="val")
core_message = CoreMessage(messageBody=mt2)
serialized = core_message.serialize()
deserialized = CoreMessage.deserialize(serialized)
print(deserialized.messageBody)

预期结果:MessageTypeTwo(val='val')
实际结果:MessageTypeOne()

原因分析

Avro联合类型的解析逻辑是按定义顺序尝试匹配类型。由于MessageTypeOne没有任何字段,Avro会认为任何记录都符合它的结构(Avro默认允许额外字段存在),所以反序列化时会优先匹配第一个符合条件的MessageTypeOne,而不是实际的MessageTypeTwo。

解决方案

有两种可行的解决方式:

方案1:给无字段类添加标识字段

给MessageTypeOne添加唯一字段,让Avro能区分不同类型:

@dataclass
class MessageTypeOne(AvroModel):
    message_type: str = "type_one"  # 添加唯一标识字段
    class Meta:
        namespace = "Messages.type.one"

@dataclass
class MessageTypeTwo(AvroModel):
    message_type: str = "type_two"
    val: typing.Union[None, str]
    class Meta:
        namespace = "Messages.type.two"

反序列化时,Avro会根据字段值匹配对应的类型,不会再错误选择MessageTypeOne。

方案2:使用dataclasses-avroschema的鉴别器功能

通过Meta类的discriminator字段指定类型鉴别标识,序列化时自动带上类型信息,反序列化时精准匹配:

@dataclass
class MessageTypeOne(AvroModel):
    class Meta:
        namespace = "Messages.type.one"
        discriminator = "message_type"  # 指定鉴别字段名
        schema_extra = {"message_type": "type_one"}  # 该类型的固定标识值

@dataclass
class MessageTypeTwo(AvroModel):
    val: typing.Union[None, str]
    class Meta:
        namespace = "Messages.type.two"
        discriminator = "message_type"
        schema_extra = {"message_type": "type_two"}

@dataclass
class CoreMessage(AvroModel):
    messageBody: typing.Union[
        MessageTypeOne,
        MessageTypeTwo,
    ]

使用鉴别器后,序列化的数据会包含message_type字段,反序列化时会根据该字段的值直接匹配对应的类型,避免顺序匹配导致的错误。

验证

修改后重新运行序列化反序列化代码,输出将为MessageTypeTwo(val='val'),符合预期。

内容的提问来源于stack exchange,提问作者Oth Mane

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 01:55:21