有没有办法将原始byte []反序列化为thrift对象而不知道它的thrift类型?

zho*_*hou 2 cross-platform thrift cross-language message-queue protocol-buffers

我正在运行一个需要的项目

  • 不同编程语言之间的相互通信(主要是java,c ++).
  • 可以序列化/反序列化为二进制格式和json格式.
  • IDL为不同语言生成类代码

虽然我们不需要其RPC功能,但Thrift完全符合这些标准.我们将通过MQ发送/接收序列化的thrift数据.序列化对象非常简单.但是,当涉及反序列化时,我们不能做这样的事情:

byte[] data = recv();
Object object = TDeserializer.deserialize(data);
if (object instanceof TypeA) {
    TypeA a = (TypeA) object;
} else if (object instanceof TypeB) {
    TypeB b = (TypeB) object;
}
Run Code Online (Sandbox Code Playgroud)

似乎我们必须告诉thrift它需要反序列化到哪个结构:

byte[] data = recv();
TypeA a;
TDeserializer.deserialize(a, data);
Run Code Online (Sandbox Code Playgroud)

只是想知道是否有办法在不知道其确切类型的情况下将原始数据反序列化为thrift对象.

谢谢!!

Wil*_*ire 11

Thrift序列化消息本身不包含类型信息,因此反序列化器必须知道消息数据类型.但是,可以将所有必要的数据类型包装成联合.

节俭代码:

union Message {
    1: TypeA a;
    2: TypeB b;
}
Run Code Online (Sandbox Code Playgroud)

反序列化代码:

byte[] data = recv();
Message msg;
TDeserializer.deserialize(msg, data);
<find out message type with msg.getSetField()>
Run Code Online (Sandbox Code Playgroud)

如果需要添加新消息类型,只需将另一个字段添加到union中即可.如果您不触摸旧字段ID,则将保留向后兼容性:

union Message {
    1: TypeA a;
    2: TypeB b;
    3: TypeC c; <-- OK
}
Run Code Online (Sandbox Code Playgroud)

您将能够接收来自旧生产者的消息(他们永远不会发送TypeC消息)并向旧消费者发送TypeA/ TypeB消息.如果您向TypeC不知道字段#3的消费者发送消息,它将获得异常.

这种方法的最大优点是类型信息非常紧凑.如果使用TCompactProtocol,在大多数情况下,类型信息只需要1个额外字节(如果字段ID Message小于127).

请注意,如果更改字段ID,则会失去向后兼容性.例如:

union Message {
    1: TypeA a;
    2: TypeC c; <-- Wrong
    3: TypeB b; <-- Wrong
    4: TypeD d; <-- OK
}
Run Code Online (Sandbox Code Playgroud)