我想知道是否可以使用google protobuf提供的反射API来序列化消息而不生成代码?协议缓冲区允许我们在解析过程之后
对Message
或Message.Builder
对象使用反射。但就我而言,我想知道是否可以用字段/值填充这些对象,然后将它们写入文件。
问问题
1831 次
2 回答
4
编码输出流
一种方法是了解消息是如何编码的,并使用CodedOutputStreamwrite*()
使用适当的方法编写消息字段。
例如编写以下消息:
message MyMessage {
int foo = 1;
string bar = 2;
}
您将使用这段代码:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
CodedOutputStream out = CodedOutputStream.newInstance(baos);
out.writeInt32(1, 1);
out.writeString(2, "s");
out.flush();
byte[] rawProtocolBuffer = baos.toByteArray();
动态消息
另一种方法是手动创建描述符,然后用于DynamicMessage
设置相应的字段,但这比CodedOutputStream
直接使用更多样板。
String messageName = "MyMessage";
FileDescriptorProto fileDescriptorProto = FileDescriptorProto
.newBuilder()
.addMessageType(DescriptorProto.newBuilder()
.setName(messageName)
.addField(FieldDescriptorProto.newBuilder()
.setName("foo")
.setNumber(1)
.setType(FieldDescriptorProto.Type.TYPE_INT32)
.build())
.addField(FieldDescriptorProto.newBuilder()
.setName("bar")
.setNumber(2)
.setType(FieldDescriptorProto.Type.TYPE_STRING)
.build())
.build())
.build();
Descriptor messageDescriptor = FileDescriptor
.buildFrom(fileDescriptorProto, new FileDescriptor[0])
.findMessageTypeByName(messageName);
DynamicMessage message = DynamicMessage
.newBuilder(messageDescriptor)
.setField(messageDescriptor.findFieldByNumber(1), 1)
.setField(messageDescriptor.findFieldByName("bar"), "s")
.build();
byte[] rawProtocolBuffer = message.toByteArray();
于 2019-08-18T04:27:19.087 回答
1
首先,您需要将 proto 文件编译成 desc 文件。
protoc --descriptor_set_out=point.desc --include_imports point.proto
然后,使用 desc 文件对消息进行编码和解码。
InputStream input = new FileInputStream("point.desc");
DescriptorProtos.FileDescriptorSet descriptorSet = DescriptorProtos.FileDescriptorSet.parseFrom(input);
DescriptorProtos.FileDescriptorProto fileDescriptorProto = descriptorSet.getFile(0);
Descriptors.Descriptor messageDescriptor = Descriptors.FileDescriptor
.buildFrom(fileDescriptorProto, new Descriptors.FileDescriptor[0])
.findMessageTypeByName("Point");
// Encoding
DynamicMessage message = DynamicMessage
.newBuilder(messageDescriptor)
.setField(messageDescriptor.findFieldByNumber(1), 10)
.setField(messageDescriptor.findFieldByNumber(2), 5)
.setField(messageDescriptor.findFieldByName("label"), "test label")
.build();
byte[] encodedBytes = message.toByteArray();
// Decoding
DynamicMessage dynamicMessage = DynamicMessage.parseFrom(messageDescriptor, encodedBytes);
int x = (int) dynamicMessage.getField(messageDescriptor.findFieldByName("x"));
int y = (int) dynamicMessage.getField(messageDescriptor.findFieldByName("y"));
String label = (String) dynamicMessage.getField(messageDescriptor.findFieldByName("label"));
于 2021-02-11T05:15:34.817 回答