如果我使用模式版本 1 序列化对象,然后将模式更新到版本 2(例如通过添加字段) - 以后反序列化对象时是否需要使用模式版本 1?理想情况下,我只想使用模式版本 2,并让反序列化对象具有在对象最初序列化后添加到模式中的字段的默认值。
也许一些代码会更好地解释......
架构1:
{"type": "record",
"name": "User",
"fields": [
{"name": "firstName", "type": "string"}
]}
架构2:
{"type": "record",
"name": "User",
"fields": [
{"name": "firstName", "type": "string"},
{"name": "lastName", "type": "string", "default": ""}
]}
使用通用的非代码生成方法:
// serialize
ByteArrayOutputStream out = new ByteArrayOutputStream();
Encoder encoder = EncoderFactory.get().binaryEncoder(out, null);
GenericDatumWriter writer = new GenericDatumWriter(schema1);
GenericRecord datum = new GenericData.Record(schema1);
datum.put("firstName", "Jack");
writer.write(datum, encoder);
encoder.flush();
out.close();
byte[] bytes = out.toByteArray();
// deserialize
// I would like to not have any reference to schema1 below here
DatumReader<GenericRecord> reader = new GenericDatumReader<GenericRecord>(schema2);
Decoder decoder = DecoderFactory.get().binaryDecoder(bytes, null);
GenericRecord result = reader.read(null, decoder);
导致 EOFException。jsonEncoder
在 AvroTypeException 中使用结果。
我知道如果我将 schema1 和 schema2 都传递给GenericDatumReader
构造函数,它将起作用,但我不想保留所有先前模式的存储库,并且还以某种方式跟踪用于序列化每个特定对象的模式。
我还尝试了代码生成方法,首先使用从 schema1 生成的 User 类序列化到文件:
User user = new User();
user.setFirstName("Jack");
DatumWriter<User> writer = new SpecificDatumWriter<User>(User.class);
FileOutputStream out = new FileOutputStream("user.avro");
Encoder encoder = EncoderFactory.get().binaryEncoder(out, null);
writer.write(user, encoder);
encoder.flush();
out.close();
然后将模式更新到版本 2,重新生成 User 类,并尝试读取文件:
DatumReader<User> reader = new SpecificDatumReader<User>(User.class);
FileInputStream in = new FileInputStream("user.avro");
Decoder decoder = DecoderFactory.get().binaryDecoder(in, null);
User user = reader.read(null, decoder);
但它也会导致 EOFException。
只是为了比较,我正在尝试做的似乎与protobufs一起工作......
格式:
option java_outer_classname = "UserProto";
message User {
optional string first_name = 1;
}
连载:
UserProto.User.Builder user = UserProto.User.newBuilder();
user.setFirstName("Jack");
FileOutputStream out = new FileOutputStream("user.data");
user.build().writeTo(out);
添加可选的 last_name 以格式化、重新生成 UserProto 和反序列化:
FileInputStream in = new FileInputStream("user.data");
UserProto.User user = UserProto.User.parseFrom(in);
正如预期的那样,user.getLastName()
是空字符串。
可以用 Avro 完成这样的事情吗?