Search code examples
c++rpcthriftc++03

How to catch all custom exceptions in a single catch statement with Apache Thrift?


I have many different exceptions defined in exception.thrift:

exception InvalidArgumentsError {
    1: string parameter
}

/**
* Server has an problem while executing a function. 
* Execution aborted.
*/
exception ServerInternalError {
    1: string parameter
}

/**
* Server answer is empty.
*/
exception NoDataError {
    1: string parameter
}

This is how i catch them in my C++ code:

catch (InvalidArgumentsError & ex) {
  std::cout << ex.parameter;
}
catch (ServerInternalError & ex) {
  std::cout << ex.parameter;
}
catch (NoDataError & ex) {
  std::cout << ex.parameter;
}
catch (apache::thrift::TException& ex) {
  std::cout << "TException:\n" << ex.what();
} catch (const std::exception& ex) {
  std::cout << ex.what();
   return;
}

I want to write something like this and catch all my exceptions:

catch (SomeBasicException& ex) {
  std::cout << ex.what();
} 
catch (const std::exception& ex) {
  std::cout << ex.what();
}

If I just catch TException and call what() I just get 'Default TException' message because derived classed do not override virtual what() method.

Generated code by thrift compiler:

class InvalidArgumentsError : public ::apache::thrift::TException {
 public:

  static const char* ascii_fingerprint; //..
  static const uint8_t binary_fingerprint[16]; //..

  InvalidArgumentsError() : parameter() {
  }

  virtual ~InvalidArgumentsError() throw() {}

  std::string parameter;

  _InvalidArgumentsError__isset __isset;

  void __set_parameter(const std::string& val) {
    parameter = val;
  }

//...

};

Solution

  • Albeit this does not really answer the question literally (@Simple did a good job at this already) I would like to propose a somewhat different approach.

    Given the code posted above:

    exception InvalidArgumentsError {
        1: string parameter
    }
    
    exception ServerInternalError {
        1: string parameter
    }
    
    exception NoDataError {
        1: string parameter
    }
    

    If we look at the pattern, we could - without loosing any information and without producing greater incompatibilities - change it into this:

    enum ErrorCode
      Success = 0, // always good to have some null value
      ServerInternalError = 1
      NoData = 2
      InvalidArguments = 3
      // add more errors here
    }
    
    exception MyServiceException {
        1: string parameter
        2: ErrorCode  code
    }
    

    I'm fully aware that this might not fit your particular problem (e.g. if there are more exception data than just a 1:parameter). But there may be cases where that approach could be worth considering. I've used it myself quite a few times.