Java 从字节数组中识别ProtoBuf类
我正在编写一个处理两条原始消息的程序,我需要处理从不同来源发送的字节[],它发送foo消息或bar消息。因为我无法确定它属于哪个消息,所以我使用了任何类(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.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
对其进行解码
这里的关键点是protobuf在消息负载中不包含类型元数据。如果有BLOB,通常无法知道消息类型Any
通过在包装器消息中编码消息类型来解决这个问题,但这里没有
如果您的设计要有一个API,它可以接受两种不同的非任何消息类型,而事先不知道它是哪种类型:那么您的设计可能很糟糕。因为这对protobuf不起作用。在电线上,一个
Foo
和a=42
的Bar
和b=42
的;有效载荷是相同的:
Foo
witha=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);
...
}