Rush, thanks for the reply and the example code. I got that working with Java server and clients without too much drama.
Still, when I read the THRIFT-378 (https://issues.apache.org/jira/browse/THRIFT-378) I get the feeling that it should not be this tedious. Quoting from the original description: --- One workaround might be to add an InternalError exception and declare every method to throw that, but this would require wrapping each method implementation on the server with a try/catch/throw block, which is ugly and repetitive (especially if there are other try/catch blocks nested) – exactly the sort of code that Thrift is good at automating away. I think the right fix would be for the server to catch runtime exceptions in the generated process methods and send back a TApplicationException. This is what some other servers (e.g., Erlang) already do.--- So what we have done is essentially implement the "workaround": boilerplate code in every method to explicitly catch internal problems and throw a custom exception. The original reporter really nailed in the last sentence - server should automatically catch run time exceptions and throw TApplicationExceptions to the client. The bug is marked as resolved for nearly 3 years, so I must be completely misunderstanding the intent. Isn't it supposed to automatically toss back to the client a TApplicationException of type INTERNAL_ERROR? Do I really have to do that by hand in every single method? Do people have to do that with C++ servers too, or is this only a problem with Java servers? It was supposedly fixed, but maybe I just don't understand the goal. When my sever hits a run time exception, the client just gets a cryptic TTransportException with no clue of what went wrong. Regards, -craig ---------------------------------------- > Subject: Re: Using TApplicationException - need example > From: [email protected] > Date: Thu, 17 May 2012 09:44:30 -0700 > To: [email protected] > > > On May 16, 2012, at 10:07 PM, Steve Angelovich wrote: > > > What is TApplicationException intended to be used for? > > > > Is there a mechanism in thrift to propagate a runtime exception from the > > server back to the client? > > > > How do others deal with a case where the caller has made an RPC call with > > an invalid argument. In Java I'd normally throw a IllegalArgumentException, > > is something like this possible in thrift or do I have to add another user > > defined exception type which will result in the caller having to deal with > > another checked exception. > > > > > > Thanks for any help > > Steve > > > > > > On 05/10/2012 05:06 PM, Craig Artley wrote: > > > > > > Hello, I want to take exceptions on the server and return them back to the > > client. For example, say the client's request leads to a run time exception > > like IllegalArgumentException. I think that TApplicationException with > > INTERNAL_ERROR is the way to do this, but I couldn't get it to work and I > > can't find any examples. > > > > In my service handler, I check the args. If they are invalid, I threw a > > TApplicationException like this > > throw new > > TApplicationException(TApplicationException.INTERNAL_ERROR,"Illegal > > argument blah blah"); > > > > It still showed up in my client as a TTransportException: > > org.apache.thrift.transport.TTransportException > > at > > org.apache.thrift.transport.TIOStreamTransport.read(TIOStreamTransport.java:132) > > > > I'm sure I am just misunderstanding something. What am I missing? Can > > anyone provide an example of robust exception handling in the server to the > > client? > > > > I read about it in THRIFT-378 > > https://issues.apache.org/jira/browse/THRIFT-378 > > > > Regards, > > -craig > > You can define your own exception types. Here's a real world example: > > ----------------------------------------------------- > File OurThriftException.thrift: > struct ExceptionInfoAll > { > 1: string name, /** The class name of the exception */ > 2: string message, /** If not a OurCustomException, this is the result of > what(). > If OurCustomException, this is the result of ex.toString(). */ > } > > struct ExceptionInfoOurCustomException > { > 1: string errorCodeName, /** The name of the error, such as DeviceNotFound > This is specific to the exception class */ > 2: i32 errorCodeValue, /** The numeric value of the error code */ > 3: string description, /** The description string defined in the exception's > EXCEPTION_TABLE */ > 4: string debugMsg, /** The debug message attached to the exception at the > throw point */ > 5: string location, /** The location information that may have been attached > at the throw point. */ > } > > struct ExceptionInfo > { > 1: ExceptionInfoAll defaultInfo, /** Available for any exception */ > 2: optional ExceptionInfoOurCustomException ourInfo, /** Available only for > OurCustomException */ > } > > exception OurThriftExceptionWire > { > 1: ExceptionInfo excInfo, /** The information extracted from the exception > that was caught by the server. */ > } > ----------------------------------------------------- > > > Once you do this, you can define a service like this: > > service MyService > { > returnType myCall ( args here) throws (1: OurThriftException. > OurThriftExceptionWire ex), > } > > On your server side, you do this (I have neglected to set the __isset values > to make the code clearer.): > > returnType myCall_handler (args) > { > > try > { > do something > } > catch (OurCustomException &ex) > { > OurThriftExceptionWire wireEx; > > wireEx.excInfo.defaultInfo = "OurCustomException"; > wireEx.excInfo.defaultInfo.message = ex.what(); > > // Extract info from OurCustomException here and pack into > wireEx.excInfo.ourInfo > > throw wireEx; > } > catch (std::exception &ex) > { > OurThriftExceptionWire wireEx; > > wireEx.excInfo.defaultInfo = "OurCustomException"; > wireEx.excInfo.defaultInfo.message = ex.what(); > > throw wireEx; > > } > } > > And on your client side you do this: > > try > { > myCall (args) > } > catch (OurThriftExceptionWire &ex) > { > // Now you have exception details from the server side. We would throw an > exception type > // specific to the library where this code is, but it would contain all the > info from > // ex.excInfo. > } > > I hope that helps. > > Best regards, > Rush
