Sergey S
Sergey S

Reputation: 930

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;
  }

//...

};

Upvotes: 2

Views: 622

Answers (2)

JensG
JensG

Reputation: 13411

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.

Upvotes: 1

Simple
Simple

Reputation: 14390

If you want to stop the repetitive typing then this might be a solution.

When you want to catch your exceptions, you write something like this:

catch (...) {
    handle_exception(print_message);
}

print_message is a function that does whatever you want with the message (in this case, print it):

void print_message(char const* const msg)
{
    std::cout << msg;
}

handle_exception is written like this:

template<typename F>
void handle_exception(F handler)
try {
    throw;
}
catch (InvalidArgumentsError const& ex) {
    handler(ex.parameter.c_str());
}
catch (ServerInternalError const& ex) {
    handler(ex.parameter.c_str());
}
catch (NoDataError const& ex) {
    handler(ex.parameter.c_str());
}
catch (apache::thrift::TException const& ex) {
    handler(ex.what());
}
catch (std::exception const& ex) {
    handler(ex.what());
}

To handle a new exception you add it to the catch clauses of the handle_exception function.

Upvotes: 2

Related Questions