Thrift java 客户端无法正确处理联合
Thrift java client cannot handle union properly
死的简单节俭联盟的例子。
环境:最新的 thrift,cpp 作为服务器,java 作为客户端
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();
}
}
不知何故,java 客户端无法正确打印字符串。 (我还写了一个 python 客户端,但这似乎可行)
要点上的完整代码:thrift file, c++ and java code
实际上您正在观察 THRIFT-1833
错误,该错误会导致编译器为联合类型生成无效的 C++ 代码。
在您的情况下,服务器写入联合类型的两个字段,而客户端始终只读取第一个 - i16_v
(剩余字节仍驻留在缓冲区中)。所以第二次读取永远不会结束,因为它在缓冲区中发现了一些意外数据。
您可以使用 struct
代替 union
并手动维护单字段逻辑。或者你可以 contribute/wait 直到错误被修复。
最后一个选项是对错误生成的 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();
+ }
死的简单节俭联盟的例子。
环境:最新的 thrift,cpp 作为服务器,java 作为客户端
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();
}
}
不知何故,java 客户端无法正确打印字符串。 (我还写了一个 python 客户端,但这似乎可行)
要点上的完整代码:thrift file, c++ and java code
实际上您正在观察 THRIFT-1833
错误,该错误会导致编译器为联合类型生成无效的 C++ 代码。
在您的情况下,服务器写入联合类型的两个字段,而客户端始终只读取第一个 - i16_v
(剩余字节仍驻留在缓冲区中)。所以第二次读取永远不会结束,因为它在缓冲区中发现了一些意外数据。
您可以使用 struct
代替 union
并手动维护单字段逻辑。或者你可以 contribute/wait 直到错误被修复。
最后一个选项是对错误生成的 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();
+ }