Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/react-native/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Protocol buffers Protobuf 3.0任何类型的包装/解包_Protocol Buffers_Pack_Unpack_Any - Fatal编程技术网

Protocol buffers Protobuf 3.0任何类型的包装/解包

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

我想知道如何将ProtobufAny类型转换为原始Protobuf消息类型,反之亦然。在Java中,从消息到任何消息都很容易:

Any.Builder anyBuilder = Any.newBuilder().mergeFrom(protoMess.build());
但是,我如何将任何解析回原始消息(例如,解析为“protomes”类型)?我可能会解析流中的所有内容,只是为了读回,但这不是我想要的。我想进行这样的转换:

ProtoMess.MessData.Builder protoMessBuilder = (ProtoMess.MessData.Builder) transformToMessageBuilder(anyBuilder)
我怎样才能做到这一点?它已经为Java实现了吗?据说有pack和unpack方法,但Java中没有。 提前感谢:)

答案可能有点晚了,但也许这仍然有助于某些人

在当前版本的协议缓冲区中,3
pack
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>();