【问题标题】:Identify ProtoBuf class from byte array从字节数组中识别 ProtoBuf 类
【发布时间】:2020-02-06 07:30:33
【问题描述】:

我正在编写一个处理两个原始消息的程序,我需要处理从不同来源发送的字节 [] 发送 foo 消息或 bar 消息。由于我无法确定它属于哪条消息,因此我使用 Any Class(与 protobuf 一起提供)来解析字节数组并 查找它属于哪个类,但遇到编译时错误。有没有其他方法可以用来检测我将来是否添加了更多的 proto 消息类?

//Foo.proto

syntax = "proto3";

option java_outer_classname = "FooProto";

message Foo {
    int32 a = 1;
}

和第二个原型

//Bar.proto
syntax = "proto3";

option java_outer_classname = "BarProto";

message Bar {
    int32 b = 1;
}

代码:

Any anyEvent = Any.parseFrom(protoBytes);
if (any.is(Foo.class)
{
  Foo foo = any.unpack(Foo.class);
  ...
} else {
  Bar bar = any.unpack(Bar.class);
  ...
}

尝试调用 any.is() 时 if 语句出错:

Any类型中的方法is(Class)不适用于参数(Class)

【问题讨论】:

    标签: java protocol-buffers proto


    【解决方案1】:

    Any 不代表“任何”;它的意思是“通过 Any 序列化的类型”。如果您没有使用Any存储它:您不能通过Any解码它。

    这里的关键点是 protobuf 在消息负载中不包含类型元数据。如果您有 BLOB,您通常不知道消息类型是什么。 Any 通过在包装消息中编码消息类型 解决了这个问题,但这里没有。


    如果您的设计是让 API 接受两种不同的非Any 消息类型,而事先不知道它是哪一种:您的设计可能很糟糕。因为 对 protobuf 不起作用。在网络上,Fooa=42Barb=42 之间字面上没有区别;有效载荷相同

    Fooa=42 是字节08 2ABarb=42 是字节 08 2A08 表示“字段 1,编码为 varint”,2A 是原始值为 42 的 varint。

    更好的设计可能是包装消息特定于您的场景

    message RootMessage {
      oneof test_oneof {
         Foo foo = 1;
         Bar bar = 2;
      }
    }
    

    这添加了一个包装层类似于 Any 的工作方式,但效率更高 - 它只知道如何区分已知类型为整数,而不必处理所有可能的类型(作为根类型名称)。

    【讨论】:

    • 感谢有关 Any 的信息,问题是 foo 消息已经从源生成,并且设计无法更改。有没有其他解决办法?
    • @Santosh 只是如图所示的两种类型吗?在 那个 场景中,我可能会向 Bar 添加一个枚举字段(字段 2),默认值为 0=Foo,1=Bar,并在新的生产者上包含该值和 1=Bar - 将所有内容解码为a Bar,但如果枚举字段显示 Foo,则将其解释为 Foo(只需读取 b 并假装它是 a)。不过,这仅适用于字段类型相同;如果 Foo 有一个 int32 a=1 而 Bar 有一个字符串 b=1,它就不起作用。
    • @santosh 要记住的关键是二进制协议中的字段名称无关;它们不被发送,也不用于解码;只有数字很重要(及其字段类型)
    • 定义的数据类型与我在问题中提到的不同,字段类型不匹配,很难识别它所属的类。
    • @Santhosh 是的,这很难;那么,您最好的选择可能是使用“阅读器”API 来检查有效负载并查看它具有哪些字段和线路类型,看看您是否可以手动识别哪个是哪个;最终,protobuf 并不适合您在这里尝试做的事情 - 它想要提前知道目标类型
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-01-05
    • 1970-01-01
    • 2015-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多