从字节数组中识别 ProtoBuf class

Identify ProtoBuf class from byte array

我正在编写一个处理两个原型消息的程序,我需要处理从不同源发送的 byte[],这些源发送 foo 消息或 bar 消息。因为我无法弄清楚它属于哪条消息,所以我使用 Any Class (与 protobuf 一起提供)来解析字节数组和 找到它属于哪个 class,但遇到编译时错误。有没有其他方法可以用来检测我将来是否添加更多原型消息 classes?

//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 语句出错:

The method is(Class< T>) in the type Any is not applicable for the arguments (Class< Foo>)

Any不代表"any";这意味着 "a type serialized via Any"。如果你没有 store 它与 Any: 你不能 decode 通过 Any.

这里的关键点是 protobuf 不在消息负载中包含类型元数据。如果您有 BLOB,您通常无法知道消息类型是什么。 Any 通过在包装消息 中对消息类型 进行编码来解决此问题,但您不会在此处使用它。


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

Fooa=42 是字节数 08 2ABarb=42 是字节 08 2A08 表示 "field 1, encoded as a varint",2A 是原始值为 42 的 varint。

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

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

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