问题描述:
当方法返回值为thrift基本类型(i64,bool...)时,客户端无法捕捉异常。
ps.当方法返回值为用户定义的类型时,不会出现该问题。
注意 thrift 版本0.8
跟踪thrift代码发现,问题出现的原因:
step 1: 服务端,写数据
(基本类型) 不会先判断返回值是否为空,基本类型也无法判断是否为空
oprot.writeStructBegin(STRUCT_DESC);
oprot.writeFieldBegin(SUCCESS_FIELD_DESC);
oprot.writeI64(struct.success);
oprot.writeFieldEnd();
(用户定义类型) 会先判断返回值是否为空
if (struct.success != null) {
oprot.writeFieldBegin(SUCCESS_FIELD_DESC);
{
oprot.writeListBegin(new org.apache.thrift.protocol.TList(org.apache.thrift.protocol.TType.STRUCT, struct.success.size()));
for (Province _iter3 : struct.success)
{
_iter3.write(oprot);
}
oprot.writeListEnd();
}
oprot.writeFieldEnd();
}
}
step 2: 客户端读数据
(基本类型) 服务端写数据时,一定会写入返回值的TField,所以读到的第一个TFIELD 一定会进入case0. 其中执行了 struct.setSuccessIsSet(true); 方法标示 返回值已写入
switch (schemeField.id) {
case 0: // SUCCESS
if (schemeField.type == TType.I64) {
struct.success = iprot.readI64();
struct.setSuccessIsSet(true);
}
else {
TProtocolUtil.skip(iprot, schemeField.type);
}
break;
case 1: // USER_EXCEPTION
//................
default:
TProtocolUtil.skip(iprot, schemeField.type);
}
(用户定义类型) 服务端写数据时,经过判断未写入返回值TField, 因此直接进入case 1
switch (schemeField.id) {
case 0: // SUCCESS
// ................
break;
case 1: // COMMON_EXCEPTION
// .................
}
step 3: 客户端处理返回结果 执行recv_****方法时
if (result.isSetSuccess()) {
return result.success;
}
if (result.commonException != null) {
throw result.commonException;
}
(基本类型) 由于基本类型在step2中执行了setSuccessIsSet(true);
因此第一个if总是为真,在这步方法已经返回。
不能够进入第二个if.捕捉异常
(用户定义类型) 用户类型。如果产生异常则跳过第一个if,能够在第二个if块中捕捉到异常
我想到的解决方法:
方法1. 更改step1
oprot.writeStructBegin(STRUCT_DESC);
oprot.writeFieldBegin(SUCCESS_FIELD_DESC);
oprot.writeI64(struct.success);
oprot.writeFieldEnd();
更改为
oprot.writeStructBegin(STRUCT_DESC);
if (this.isSetSuccess()) {
oprot.writeFieldBegin(SUCCESS_FIELD_DESC);
oprot.writeI64(struct.success);
oprot.writeFieldEnd();
}
方法2. 更改step3
将recv_****方法中
if (result.isSetSuccess()) {
return result.success;
}
if (result.commonException != null) {
throw result.commonException;
}
更改顺序变为
if (result.commonException != null) {
throw result.commonException;
}
if (result.isSetSuccess()) {
return result.success;
}
问题得到解决
但是由于 这样需要为每个生成的Iface修改代码,开发代价太大。所以想请教下大牛们是如何解决这个问题的。
thrift 0.8 java客户端无法catch异常
最新推荐文章于 2024-10-12 22:35:37 发布