如何从FileDescriptorSet中获取Descriptor以重构Protobuf动态消息
从FileDescriptorSet反向获取Descriptor的实现方案
实现步骤
要从生成的FileDescriptorSet中获取可用的Descriptor对象,按以下步骤操作即可:
- 把
FileDescriptorSet中存储的FileDescriptorProto反序列化为FileDescriptor实例 - 从
FileDescriptor中按目标消息的全限定名提取对应的Descriptor - 使用得到的
Descriptor解析动态消息
完整代码示例
import com.google.protobuf.DescriptorProtos.FileDescriptorProto; import com.google.protobuf.DescriptorProtos.FileDescriptorSet; import com.google.protobuf.Descriptors.Descriptor; import com.google.protobuf.Descriptors.FileDescriptor; import com.google.protobuf.DynamicMessage; import java.util.ArrayList; import java.util.List; // 假设你已经拿到了传输到对端的FileDescriptorSet实例和消息字节数组 FileDescriptorSet receivedFileDescriptorSet = ...; byte[] myObjectBytes = ...; List<FileDescriptorProto> fileProtoList = receivedFileDescriptorSet.getFileList(); List<FileDescriptor> resolvedDependencies = new ArrayList<>(); Descriptor targetDescriptor = null; try { // 构造所有FileDescriptor实例,有依赖的情况下需要按依赖顺序处理 for (FileDescriptorProto fileProto : fileProtoList) { FileDescriptor fd = FileDescriptor.buildFrom(fileProto, resolvedDependencies.toArray(new FileDescriptor[0])); resolvedDependencies.add(fd); } // 按目标消息全限定名查找Descriptor,此处替换为你实际的消息全限定名(包名+消息名) String targetMessageFullName = "your.package.YourMessageName"; for (FileDescriptor fd : resolvedDependencies) { targetDescriptor = fd.findMessageTypeByName(targetMessageFullName); if (targetDescriptor != null) { break; } } if (targetDescriptor == null) { throw new RuntimeException("找不到对应消息的Descriptor,请检查全限定名是否正确"); } // 解析动态消息,和你预期的调用逻辑完全一致 DynamicMessage parsedMessage = DynamicMessage.parseFrom(targetDescriptor, myObjectBytes); // 后续可直接操作parsedMessage获取字段内容 } catch (Exception e) { // 处理Descriptor构造或消息解析异常 e.printStackTrace(); }
注意事项
- 构造
FileDescriptor时需要传入所有依赖的FileDescriptor实例,如果你生成FileDescriptorSet时只添加了目标消息的单个proto文件,且该proto有import其他依赖proto,需要把所有依赖的proto对应的FileDescriptorProto都添加到FileDescriptorSet中,否则会构造失败 - 目标消息的全限定名需要和proto文件中定义的包名、消息名完全一致,大小写敏感
内容的提问来源于stack exchange,提问作者Oleg Zhurakousky
相关产品推荐
相关产品推荐

