设想 -
客户端使用 Avro Reflect Datum Writer 序列化 POJO 并将 GenericRecord 写入文件。
通过反射获得的模式是这样的(注意顺序A、B、D、C)-
{
"namespace": "storage.management.example.schema",
"type": "record",
"doc": "Example schema for testing",
"name": "Event",
"fields": [
....
....
{ "name": "A", "type": "string" },
{ "name": "B", "type": "string" },
{ "name": "D", "type": "string" },
{ "name": "C", "type": "string" },
....
....
]
}
代理读取文件并使用默认模式(注意顺序 - A、B、C、D)来反序列化记录的子集(保证客户端拥有这些字段)
{
"namespace": "storage.management.example.schema",
"type": "record",
"doc": "Example schema for testing",
"name": "Event",
"fields": [
{ "name": "A", "type": "string" },
{ "name": "B", "type": "string" },
{ "name": "C", "type": "string" },
{ "name": "D", "type": "string" }
]
}
问题 :
使用上述子集模式的反序列化会导致以下异常 -
Caused by: java.io.IOException: Invalid int encoding
at org.apache.avro.io.BinaryDecoder.readInt(BinaryDecoder.java:145)
at org.apache.avro.io.BinaryDecoder.readString(BinaryDecoder.java:259)
at org.apache.avro.io.ResolvingDecoder.readString(ResolvingDecoder.java:201)
at org.apache.avro.generic.GenericDatumReader.readString(GenericDatumReader.java:430)
at org.apache.avro.generic.GenericDatumReader.readString(GenericDatumReader.java:422)
at org.apache.avro.generic.GenericDatumReader.readWithoutConversion(GenericDatumReader.java:180)
at org.apache.avro.generic.GenericDatumReader.read(GenericDatumReader.java:152)
at org.apache.avro.generic.GenericDatumReader.readField(GenericDatumReader.java:240)
at org.apache.avro.generic.GenericDatumReader.readRecord(GenericDatumReader.java:230)
但是,如果子集模式还按 A、B、D、C 的顺序指定字段,则反序列化会成功。(与客户端模式相同)
这种行为是预期的吗?我认为 Avro 仅依赖于字段名称来构建记录,而不依赖于排序。
有什么解决办法吗?不同的客户端可能有不同的顺序,我无法强制排序,因为模式是通过反射生成的。