【发布时间】:2016-03-24 06:15:01
【问题描述】:
我无法在使用 C GLib 序列化的 Java Thrift 对象中反序列化。 我的序列化代码如下(在我的问题here 之后提出的解决方案):
ThriftMemoryBuffer* tbuffer = g_object_new(THRIFT_TYPE_MEMORY_BUFFER,
"buf_size", 2048, NULL);
ThriftTransport *transport = NULL;
ThriftProtocol* protocol = NULL;
GError* error = NULL;
if (tbuffer) {
transport = THRIFT_TRANSPORT(tbuffer);
thrift_transport_open(transport, &error);
protocol =
THRIFT_PROTOCOL(
g_object_new(THRIFT_TYPE_BINARY_PROTOCOL, "transport", transport, NULL));
if (protocol) {
ExceptionData* exception_data = g_object_new(TYPE_EXCEPTION_DATA, "ex_sign",
exception_signature, "cl_sign", class_signature, "caught",
catch_method != NULL,
NULL);
if (exception_data) {
ThriftStructClass* cls = THRIFT_STRUCT_CLASS(EXCEPTION_DATA_GET_CLASS(exception_data));
int write_len = cls->write(exception_data, protocol, &error);
if(tbuffer->buf != NULL) {
printf("Write len %i bytes\n", write_len);
printf("Data sending: %s, %s, %b \n", exception_data->ex_sign, exception_data->cl_sign, exception_data->caught);
send_kafka_message((const void *)tbuffer->buf, write_len);
}
g_object_unref(exception_data);
}
g_object_unref(protocol);
}
if (thrift_transport_is_open(transport)) {
thrift_transport_close(transport, &error);
}
g_object_unref(tbuffer);
}
Java 中的反序列化代码:
TDeserializer deserializer = new TDeserializer();
ExceptionData ex = new ExceptionData();
try {
byte[] binData = tuple.getBinary(0);
_logger.info("Bin data length: " + binData.length);
_logger.info("HEX data: " + DatatypeConverter.printHexBinary(binData));
deserializer.deserialize(ex, binData);
} catch (TException e) {
_logger.error(e);
}
_logger.info("Deserialized object: " + ex);
它总是失败,异常类似于:
org.apache.thrift.protocol.TProtocolException: Required field 'caught' was not found in serialized data!
我的节俭计划是:
struct ExceptionData {
1: required string ex_sign, // exception signature
2: required string cl_sign, // class signature where exception was thrown
3: required bool caught // whether exception was caught or not
}
发送和接收消息的长度相同。但不知何故,在 Java 方面我无法重现对象。
可能有人遇到过类似的问题?
更新:
示例输出:
ExceptionData("Ljava/lang/ClassNotFoundException;", "Ljava/net/URLClassLoader;", true)
HEX data: 40890DE0297F00004C000000800000000100000000000000010000000000000000000000000000000000000000000000007E0DE0297F00000100000000000000000000000000000090D900E0
HEX data(1): 00880D109D7F00004E000000800000000100000000000000010000000000000000000000000000000000000000000000007E0D109D7F000001000000000000000000000000000000507F0D109D7F
HEX data(2): 00880D4CF57F00004E000000800000000100000000000000010000000000000000000000000000000000000000000000007E0D4CF57F000001000000000000000000000000000000507F0D4CF57F
我注意到上面的输出有些奇怪:
- 为什么对于相同的输入数据,它会序列化为不同的输出?
- 为什么会有这么多零?
我尝试序列化-反序列化同一对象仅使用 Java,这是示例输出:
ExceptionData("Ljava/lang/ClassNotFoundException;", "Ljava/net/URLClassLoader;", true)
HEX data: 0B0001000000224C6A6176612F6C616E672F436C6173734E6F74466F756E64457863657074696F6E3B0B0002000000194C6A6176612F6E65742F55524C436C6173734C6F616465723B0200030100
如果我只正确使用 Java 对象序列化-反序列化,并且 HEX 输出对于相同的输入数据是相同的
UPD2:
在发送到 kafka 之前,对相同的 tbuffer->buf 进行了两次连续的十六进制转储。看起来缓冲区在发送前包含错误的数据:
call 1 buf:
0000 00 88 0d 2c ce 7f 00 00 4e 00 00 00 80 00 00 00 ...,....N.......
0010 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 ................
0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0030 00 7e 0d 2c ce 7f 00 00 01 00 00 00 00 00 00 00 .~.,............
0040 00 00 00 00 00 00 00 00 50 e2 00 2c ce 7f ........P..,..
call 2 buf:
0000 80 88 0d b8 08 7f 00 00 4e 00 00 00 80 00 00 00 ........N.......
0010 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 ................
0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0030 00 e1 00 b8 08 7f 00 00 01 00 00 00 00 00 00 00 ................
0040 00 00 00 00 00 00 00 00 20 88 0d b8 08 7f ........ .....
【问题讨论】:
-
所有字段都标记为
required。除了这是否是一个好的决定的问题之外,required的字面意思是:字段 必须 出现在要反序列化的数据流中。大多数实现在反序列化之前和之后检查required成员的存在,这就是您在此处看到的。 -
我们可以看看数据样本吗?可能打印的十六进制值?
-
在问题中添加了示例输出和一些 cmets(在 UPD 之后)
-
确实如此。第一个数据 BLOB(有很多零的)是完全错误的。在将缓冲区内容从 C/glib 传输到 Java 的过程中出现问题,或者缓冲区内容本身从一开始就是错误的。数据看起来像一些带有一些指针的反序列化内存,因此在某些时候可能缺少指针取消引用或地址运算符。或者……像这样。
-
是的,看起来像那样。在客户端序列化后立即添加十六进制转储缓冲区(UPD2)
标签: java c serialization deserialization thrift