Java 从字节数组中识别ProtoBuf类

Java 从字节数组中识别ProtoBuf类,java,protocol-buffers,proto,Java,Protocol Buffers,Proto,我正在编写一个处理两条原始消息的程序,我需要处理从不同来源发送的字节[],它发送foo消息或bar消息。因为我无法确定它属于哪个消息,所以我使用了任何类(protobuf附带)来解析字节数组并 查找它所属的类,但遇到编译时错误。如果我将来添加更多的原始消息类,是否还有其他方法可以用来检测 //Foo.proto syntax = "proto3"; option java_outer_classname = "FooProto"; message Foo { int32 a = 1

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

//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;
}
代码:

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

该方法(类)的类型为Any,不适用于参数(类


Any
不代表“Any”;它的意思是“通过任何方式序列化的类型”。如果未将其与
Any
一起存储:则无法通过
Any
对其进行解码

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


如果您的设计要有一个API,它可以接受两种不同的非任何消息类型,而事先不知道它是哪种类型:那么您的设计可能很糟糕。因为这对protobuf不起作用。在电线上,一个
Foo
a=42
Bar
b=42
;有效载荷是相同的

Foo
with
a=42
是字节
082a
<带有
b=42的code>Bar
是字节
082a
08
表示“字段1,编码为变量,
2A
是具有原始值42的变量

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

消息根消息{
测试之一{
Foo-Foo=1;
Bar=2;
}
}

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

感谢提供有关Any的信息,问题是foo消息已经从源生成,并且无法更改设计。还有其他的解决方案吗?@Santosh它只是如图所示的两种类型吗?在这种情况下,我可能会向Bar添加一个枚举字段(字段2),默认值为0=Foo,1=Bar,并在新的producer上使用1=Bar包含该值-将所有内容解码为Bar,但如果枚举字段表示Foo,则将其解释为Foo(只需读取b并将其假装为a)。但是,这只适用于字段类型相同的情况;如果Foo有一个int32a=1,Bar有一个字符串b=1,那么它就不起作用了。@santosh需要记住的关键是,字段名在二进制协议中并不重要;它们不被发送,也不用于解码;只有数字(及其字段类型)重要。定义的数据类型与我在问题中提到的不同,字段类型不匹配,因此很难识别它所属的类。@Santhosh是的,这使它非常困难;那么,您最好的选择可能是使用“reader”API来检查有效负载,看看它有哪些字段和导线类型,看看您是否可以手动识别哪个是哪个;归根结底,protobuf并不适合您在这里尝试做的事情——它希望提前知道目标类型
Any anyEvent = Any.parseFrom(protoBytes);
if (any.is(Foo.class)
{
  Foo foo = any.unpack(Foo.class);
  ...
} else {
  Bar bar = any.unpack(Bar.class);
  ...
}