Protocol buffers Protobuf 3.0任何类型的包装/解包
我想知道如何将ProtobufAny类型转换为原始Protobuf消息类型,反之亦然。在Java中,从消息到任何消息都很容易:Protocol buffers Protobuf 3.0任何类型的包装/解包,protocol-buffers,pack,unpack,any,Protocol Buffers,Pack,Unpack,Any,我想知道如何将ProtobufAny类型转换为原始Protobuf消息类型,反之亦然。在Java中,从消息到任何消息都很容易: Any.Builder anyBuilder = Any.newBuilder().mergeFrom(protoMess.build()); 但是,我如何将任何解析回原始消息(例如,解析为“protomes”类型)?我可能会解析流中的所有内容,只是为了读回,但这不是我想要的。我想进行这样的转换: ProtoMess.MessData.Builder protoMes
Any.Builder anyBuilder = Any.newBuilder().mergeFrom(protoMess.build());
但是,我如何将任何解析回原始消息(例如,解析为“protomes”类型)?我可能会解析流中的所有内容,只是为了读回,但这不是我想要的。我想进行这样的转换:
ProtoMess.MessData.Builder protoMessBuilder = (ProtoMess.MessData.Builder) transformToMessageBuilder(anyBuilder)
我怎样才能做到这一点?它已经为Java实现了吗?据说有pack和unpack方法,但Java中没有。
提前感谢:)
答案可能有点晚了,但也许这仍然有助于某些人
在当前版本的协议缓冲区中,3pack
和unpack
是可用的
在您的示例中,可以按如下方式进行打包:
anyanymessage=Any.pack(protoMess.build());
打开包装,如:
ProtoMess-ProtoMess=anyMessage.unpack(ProtoMess.class);
下面是使用嵌套的
Any
消息处理协议缓冲区消息的完整示例:
协议缓冲区文件
带有嵌套任何消息的简单协议缓冲区文件可能如下所示:
syntax=“proto3”;
导入“google/protobuf/any.proto”;
消息父消息{
字符串文本=1;
google.protobuf.Any childMessage=2;
}
然后,可能的嵌套消息可以是:
syntax=“proto3”;
消息子消息{
字符串文本=1;
}
包装
要生成完整消息,可以使用以下功能:
public ParentMessage createMessage(){
//创建子消息
ChildMessage.Builder childMessageBuilder=ChildMessage.newBuilder();
setText(“子文本”);
//创建父消息
ParentMessage.Builder parentMessageBuilder=ParentMessage.newBuilder();
parentMessageBuilder.setText(“父文本”);
parentMessageBuilder.setChildMessage(Any.pack(childMessageBuilder.build());
//回信
返回parentMessageBuilder.build();
}
拆包
要从父消息读取子消息,可以使用以下功能:
public ChildMessage readChildMessage(ParentMessage ParentMessage){
试一试{
返回parentMessage.getChildMessage().unpack(ChildMessage.class);
}捕获(无效的RotocolBufferException e){
e、 printStackTrace();
返回null;
}
}
编辑:
如果打包的邮件可以有不同的类型,则可以读取typeUrl
,并使用反射来解压缩邮件。假设您有子消息ChildMessage1
和ChildMessage2
,您可以执行以下操作:
@SuppressWarnings(“未选中”)
公共消息readChildMessage(ParentMessage ParentMessage){
试一试{
Any childMessage=parentMessage.getChildMessage();
字符串clazzName=childMessage.getTypeUrl().split(“/”[1];
String clazzPackage=String.format(“package.%s”,clazzName);
Class clazz=(Class)Class.forName(clazzPackage);
返回childMessage.unpack(clazz);
}捕获(ClassNotFoundException | InvalidProtocolBufferException e){
e、 printStackTrace();
返回null;
}
}
为了进一步处理,您可以使用instanceof
确定消息的类型,这不是很有效。如果您想获取某种类型的消息,应直接比较typeUrl
:
public ChildMessage1 readChildMessage(ParentMessage ParentMessage){
试一试{
Any childMessage=parentMessage.getChildMessage();
字符串clazzName=childMessage.getTypeUrl().split(“/”[1];
if(clazzName.equals(“ChildMessage1”)){
返回childMessage.unpack(“ChildMessage1.class”);
}
返回空
}捕获(无效的RotocolBufferException e){
e、 printStackTrace();
返回null;
}
}
我知道这个问题很老了,但在我寻找答案的时候它还是出现了。使用@sundance-answer,我必须用不同的方式来回答这个问题。问题在于实际消息是实际类的子类。所以它需要一美元
for(Any x : in.getDetailsList()){
try{
String clazzName = x.getTypeUrl().split("/")[1];
String[] split_name = clazzName.split("\\.");
String nameClass = String.join(".", Arrays.copyOfRange(split_name, 0, split_name.length - 1)) + "$" + split_name[split_name.length-1];
Class<Message> clazz = (Class<Message>) Class.forName(nameClass);
System.out.println(x.unpack(clazz));
} catch (Exception e){
e.printStackTrace();
}
}
及
只是为了增加信息,以防有人有同样的问题。。。当前要解包,您必须执行以下操作(c#.netcore 3.1 Google.Protobuf 3.11.4)
Foo myobject=anyMessage.Unpack();
除了此readChildMessage
之外,没有其他方法了吗?如果我发现有几十条不同的信息可能会出现呢?只需添加新的try catch
块?即使是switch case
之类的东西也是绝对不能接受的。好问题,我忘了补充一下,你可以通过typeURL
获得打包邮件的名称。这允许通过反射解压任何消息,或直接决定如何处理消息。我在我的答案中添加了两个例子,我希望这会有所帮助。太好了!它帮助了我!childMessage.getTypeUrl().split(“/”[1];不会正确给出java包的名称吗?它将提供proto包,因此无法工作。
syntax = "proto3";
package cb_grpc.msg.Main;
service QueryService {
rpc anyService (AnyID) returns (QueryResponse) {}
}
enum Buckets {
main = 0;
txn = 1;
hxn = 2;
}
message QueryResponse{
string content = 1;
string code = 2;
}
message AnyID {
Buckets bucket = 1;
string docID = 2;
repeated google.protobuf.Any details = 3;
}
syntax = "proto3";
package org.querc.cb_grpc.msg.database;
option java_package = "org.querc.cb_grpc.msg";
option java_outer_classname = "database";
message TxnLog {
string doc_id = 1;
repeated string changes = 2;
}
Foo myobject = anyMessage.Unpack<Foo>();