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

avro::jsonEncoder编码Union类型数据抛出异常的解决办法

问题描述

我在data_avro.json文件中定义了如下AVRO Schema:

[
 {
     "namespace": "my.data",
     "type": "record",
     "name": "Data1",
     "fields" : [
         {"name": "i", "type": "int"}
     ]
 },
 {
     "namespace": "my.data",
     "type": "record",
     "name": "Data2",
     "fields" : [
         {"name": "u", "type": "double"},
         {"name": "val", "type": "int"}
     ]
 }
]

尝试通过以下代码进行数据编码:

avrodata::Data1 data1;
data1.i = 1;

avrodata::Data2 data2;
data2.val = 0;
data2.u = 2.5;

std::ifstream ifs("data_avro.json");
avro::ValidSchema schemas;

std::string err;

if (!avro::compileJsonSchema(ifs, schemas, err))
    std::cerr << "compileJsonSchema error : " << err << std::endl;
else
    std::cout << "compileJsonSchema success" << std::endl;

auto encoder = avro::jsonEncoder(schemas);
auto out = avro::memoryOutputStream();
encoder->init(*out);

avro::encode(*encoder, data1); // 此处抛出avro::Exception异常

运行后出现错误,输出如下:

compileJsonSchema success
terminate called after throwing an instance of 'avro::Exception'
  what():  Invalid operation. Expected: Int got Union

使用avro::binaryEncoder时可以正常工作,但avro::jsonEncoder不行,请问如何使用avro::jsonEncoder完成该数据的编码?


解决方案

问题原因

你传入的Schema是多个Record组成的数组,编译后会被解析成Union类型(即[Data1, Data2]的联合类型),而非两个独立的Schema。binaryEncoder对Union类型的处理较为宽松,但jsonEncoder要求必须明确指定要编码的是Union中的哪一个分支类型,不能直接传入具体的Record对象。

解决步骤

要正确使用jsonEncoder编码Union类型的数据,需通过avro::GenericDatum包装具体数据,并指定对应的Schema分支:

  1. 从编译后的Union Schema中获取对应Record的子Schema
  2. 创建GenericDatum并写入具体数据,指定Union分支索引
  3. 对GenericDatum执行编码操作

完整修改后的代码

avrodata::Data1 data1;
data1.i = 1;

avrodata::Data2 data2;
data2.val = 0;
data2.u = 2.5;

std::ifstream ifs("data_avro.json");
avro::ValidSchema schemas;

std::string err;

if (!avro::compileJsonSchema(ifs, schemas, err))
    std::cerr << "compileJsonSchema error : " << err << std::endl;
else
    std::cout << "compileJsonSchema success" << std::endl;

auto encoder = avro::jsonEncoder(schemas);
auto out = avro::memoryOutputStream();
encoder->init(*out);

// 处理Data1的编码:指定Union分支0
const avro::ValidSchema& data1Schema = schemas.unionBranch(0);
avro::GenericDatum datum(schemas);
datum.setUnionIndex(0);
avro::GenericDatum recordDatum(data1Schema);
recordDatum.field("i") = data1.i;
datum.unionDatum() = recordDatum;

avro::encode(*encoder, datum);

// 完成编码并输出JSON结果
encoder->flush();
auto buffer = avro::memoryOutputStream::cast(*out)->buffer();
std::string jsonStr(buffer->begin(), buffer->end());
std::cout << jsonStr << std::endl;

额外说明

如果你的需求是分别编码两个独立的Record而非Union类型,建议修改data_avro.json,每次仅传入单个Record的Schema;或在代码中分别编译两个Schema,而非一次性编译整个数组。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 06:43:25