`
zhengjie110120
  • 浏览: 2296 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

thrift 0.8 java客户端无法catch异常

 
阅读更多


问题描述:
    当方法返回值为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修改代码,开发代价太大。所以想请教下大牛们是如何解决这个问题的。
   
   

分享到:
评论
1 楼 zhengjie110120 2012-05-16  
换成0.6.1 没有这个问题

相关推荐

Global site tag (gtag.js) - Google Analytics