Dead simple thrift union example.
Env: latest thrift, cpp as server, java as client
mytest.thrift
:
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();
}
}
Somehow, java client cannot print out string properly. (I also wrote a python client, but that seems work)
Full code on gist here: thrift file, c++ and java code
Actually you are observing THRIFT-1833
bug which cause compiler to produce invalid C++ code for union types.
In your case server writes both fields of union type while client always reads only first one - i16_v
(remaining bytes are still resides in buffer). So second read never ends because it finds some unexpected data in buffer.
You can can use struct
instead of union
and maintain single-field logic manually. Or you either can contribute/wait till bug will be fixed.
The last option is applying a patch on incorrectly generated C++ source code like this:
--- 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();
+ }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With