2016-02-16 35 views
9

Przykład martwego, prostego oszczędzania. Koperta: najnowsze gospodarność, cpp jako serwer, Java jako klient mytest.thrift:Thrift klient java nie może poprawnie obsługiwać związku

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(); 
     } 
}  

Jakoś klient Java może nie drukować ciąg prawidłowo. (Ja też napisałem klienta Pythona, ale wydaje się, że praca)

pełny kod na GIST tutaj: thrift file, c++ and java code

Odpowiedz

3

Właściwie obserwujemy THRIFT-1833 błąd, który spowoduje kompilatora produkować nieprawidłowy kod C++ dla typów związków.

W twoim przypadku serwer zapisuje oba pola typu unii, podczas gdy klient zawsze czyta tylko pierwszy - i16_v (pozostałe bajty nadal znajdują się w buforze). Więc drugie czytanie nigdy się nie kończy, ponieważ znajduje nieoczekiwane dane w buforze.

Można używać struct zamiast union i utrzymywać logikę pojedynczego pola ręcznie. Albo możesz przyczynić się/poczekać, aż błąd zostanie naprawiony.

Ostatnią opcją jest stosowanie plastra na nieprawidłowo wygenerowanego kodu źródłowego C++ tak:

--- 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(); 
+ }