2016-02-16 45 views
9

死簡單的節儉聯合示例。 ENV:最新的節儉,CPP作爲服務器,Java作爲客戶端 mytest.thriftThrift 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(); 
     } 
}  

不知何故,Java客戶端不能正常打印出字符串。 (我也寫了一個Python客戶端,但似乎工作)

的完整代碼的要點在這裏:thrift file, c++ and java code

回答

3

其實你正在觀察THRIFT-1833錯誤造成編譯器生成union類型無效的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(); 
+ }