有没有一种方法可以在不生成代码的情况下编写原始数据



我想知道是否可以使用google protobuf提供的反射API来序列化消息而不生成代码

协议缓冲区允许我们在解析过程后对MessageMessage.Builder对象使用反射。但在我的情况下,我想知道我是否可以用字段/值填充这些对象,然后将它们写入文件。

编码输出流

一种方法是了解消息是如何编码的,并使用CodedOutputStream使用适当的write*()方法编写消息字段。

例如,编写以下消息:

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();

首先需要将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"));

相关内容

  • 没有找到相关文章

最新更新