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

Reply via email to