Thrift java客户端无法正常处理联合

时间:2016-02-16 22:57:45

标签: java c++ thrift unions

死亡简单的节俭联盟的例子。 环境:最新的thrift,cpp作为服务器,java作为客户端 namespace java com.wilbeibi.thrift union Value { 1: i16 i16_v, 2: string str_v, } struct Box { 1: Value value; } service MyTest { Box echoUnion(1: i32 number); }

C++ server code:

#include "MyTest.h" #include <thrift/protocol/TBinaryProtocol.h> #include <thrift/server/TSimpleServer.h> #include <thrift/transport/TServerSocket.h> #include <thrift/transport/TBufferTransports.h> using namespace ::apache::thrift; using namespace ::apache::thrift::protocol; using namespace ::apache::thrift::transport; using namespace ::apache::thrift::server; using boost::shared_ptr; class MyTestHandler : virtual public MyTestIf { public: MyTestHandler() { // Your initialization goes here } void echoUnion(Box& _return, const int32_t number) { // Your implementation goes here printf("Into echoUnion\n"); if (number % 2 == 0) { Value v; v.__set_i16_v(100); v.__isset.i16_v = true; _return.__set_value(v); printf("Even number set int32\n"); } else { Value v; v.__set_str_v("String value"); v.__isset.str_v = true; _return.__set_value(v); printf("Odd number set string\n"); } printf("echoUnion\n"); } }; int main(int argc, char **argv) { int port = 9090; shared_ptr<MyTestHandler> handler(new MyTestHandler()); shared_ptr<TProcessor> processor(new MyTestProcessor(handler)); shared_ptr<TServerTransport> serverTransport(new TServerSocket(port)); shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory()); shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory()); TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory); printf("Server is running on %d\n", port); server.serve(); return 0; }

java client code

// some imports here public class Client { public void startClient() { TTransport transport; try { transport = new TSocket("localhost", 9090); TProtocol protocol = new TBinaryProtocol(transport); MyTest.Client client = new MyTest.Client(protocol); transport.open(); Box box = client.echoUnion(1); System.out.println(box.toString()); Box box2 = client.echoUnion(2); System.out.println(box2.toString()); transport.close(); } catch (TTransportException e) { e.printStackTrace(); } catch (TException e) { e.printStackTrace(); } } public static void main(String[] args) { Client client = new Client(); client.startClient(); } }

{{1}}

不知何故,java客户端无法正确打印出字符串。 (我还写了一个python客户端,但这似乎有用)

这里的完整代码:thrift file, c++ and java code

1 个答案:

答案 0 :(得分:3)

实际上您正在观察THRIFT-1833错误,导致编译器为联合类型生成无效的C ++代码。

在你的情况下,服务器写入两个联合类型的字段,而客户端总是只读取第一个 - i16_v(剩余的字节仍然驻留在缓冲区中)。因此,第二次读取永远不会结束,因为它在缓冲区中发现了一些意外数据。

您可以使用struct代替union并手动维护单字段逻辑。或者你可以贡献/等待直到修复bug。

最后一个选项是对错误生成的C ++源代码应用补丁:

--- mytest_types.cpp    2016-02-26 20:02:57.210652969 +0300
+++ mytest_types.cpp.old   2016-02-26 20:02:39.650652742 +0300 
@@ -80,13 +80,17 @@
apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot);
xfer += oprot->writeStructBegin("Value");

-  xfer += oprot->writeFieldBegin("i16_v", ::apache::thrift::protocol::T_I16, 1);
-  xfer += oprot->writeI16(this->i16_v);
-  xfer += oprot->writeFieldEnd();
+  if (this->__isset.i16_v) {
+    xfer += oprot->writeFieldBegin("i16_v", ::apache::thrift::protocol::T_I16, 1);
+    xfer += oprot->writeI16(this->i16_v);
+    xfer += oprot->writeFieldEnd();
+  }

-  xfer += oprot->writeFieldBegin("str_v", ::apache::thrift::protocol::T_STRING, 2);
-  xfer += oprot->writeString(this->str_v);
-  xfer += oprot->writeFieldEnd();
+  if (this->__isset.str_v) {
+    xfer += oprot->writeFieldBegin("str_v", ::apache::thrift::protocol::T_STRING, 2);
+    xfer += oprot->writeString(this->str_v);
+    xfer += oprot->writeFieldEnd();
+  }