我正在使用 Avro 1.7.0 使用其Java 的通用表示 API,并且在处理我们当前的模式演变案例时遇到了问题。我们在这里处理的场景是通过将字段更改为与该原始类型的联合来使原始类型字段成为可选的null
。
我将使用一个简单的例子。基本上,我们的模式是:
- 初始:具有一个类型字段的记录
int
- 第二个版本:相同的记录,相同的字段名称,但类型现在是和的
null
并集int
根据 Avro 规范的架构解析章节,这种情况的解析应该是:
如果读者是一个联合,但作者不是
读者联合中与作者模式匹配的第一个模式将针对它递归解析。如果没有匹配,则发出错误信号。
我的解释是,我们应该正确地解析使用初始模式序列化的数据,因为int
它是读者模式中联合的一部分。
但是,当运行使用版本 2 读回使用版本 1 序列化的记录的测试时,我得到
org.apache.avro.AvroTypeException: Attempt to process a int when a union was expected.
这是一个测试,正好显示了这一点:
@Test
public void testReadingUnionFromValueWrittenAsPrimitive() throws Exception {
Schema writerSchema = new Schema.Parser().parse("{\n" +
" \"type\":\"record\",\n" +
" \"name\":\"NeighborComparisons\",\n" +
" \"fields\": [\n" +
" {\"name\": \"test\",\n" +
" \"type\": \"int\" }]} ");
Schema readersSchema = new Schema.Parser().parse(" {\n" +
" \"type\":\"record\",\n" +
" \"name\":\"NeighborComparisons\",\n" +
" \"fields\": [ {\n" +
" \"name\": \"test\",\n" +
" \"type\": [\"null\", \"int\"],\n" +
" \"default\": null } ] }");
// Writing a record using the initial schema with the
// test field defined as an int
GenericData.Record record = new GenericData.Record(writerSchema);
record.put("test", Integer.valueOf(10));
ByteArrayOutputStream output = new ByteArrayOutputStream();
JsonEncoder jsonEncoder = EncoderFactory.get().
jsonEncoder(writerSchema, output);
GenericDatumWriter<GenericData.Record> writer = new
GenericDatumWriter<GenericData.Record>(writerSchema);
writer.write(record, jsonEncoder);
jsonEncoder.flush();
output.flush();
System.out.println(output.toString());
// We try reading it back using the second schema
// version where the test field is defined as a union of null and int
JsonDecoder jsonDecoder = DecoderFactory.get().
jsonDecoder(readersSchema, output.toString());
GenericDatumReader<GenericData.Record> reader =
new GenericDatumReader<GenericData.Record>(writerSchema,
readersSchema);
GenericData.Record read = reader.read(null, jsonDecoder);
// We should be able to assert that the value is 10 but it
// fails on reading the record before getting here
assertEquals(10, read.get("test"));
}
我想知道我的期望是否正确(这应该成功解决吧?)或者我没有正确使用 avro 来处理这种情况。