views:

461

answers:

2

Is it a bad idea to use exception chaining when throwing RemoteExceptions? We have an RMI server that does something like this:

public Object doSomething() throws RemoteException
{
    try
    {
        return getData();
    }
    catch (CustomException ex)
    {
        throw new RemoteException(ex);
    }
}

I'm getting UnmarshallException caused by a ClassNotFoundException in my client. On the plus side, it turns out that CustomException itself IS exported. Unfortunately, another exception deep inside this guy is NOT exported, which is where the ClassNotFoundException comes in. I think the hierarchy is something like this:

RemoteException -> CustomException -> SQLException -> NotExportedException

The problem I see is that even though we can guarantee that CustomException is exported, we can't guarantee that any lower level exceptions are.

I'm leaning towards NEVER using exception chaining with RemoteExceptions because of this. Instead, I think I should probably log the stack trace on the server side and throw a plain, vanilla RemoteException with no "cause" exception chained to it. Anyone dealt with this situation before?

+3  A: 

Rather than wrapping CustomException in RemoteException, you might modify your remote interface like this:

interface Foo extends Remote {

  Object doSomething() throws CustomException, RemoteException;

}

The principle here is that only the RMI runtime should be raising RemoteExceptions; they signal some failure in the remoting, not in the application logic. In fact, the concrete implementations don't even need to declare the RemoteException.

But, that doesn't handle the case where your service is catching an exception from some third-party library, but doesn't want to expose that in a throws clause.

public Object doSomething() throws CustomException {
  try {
    return theirSvc.getData();
  } catch (ThirdPartyException ex) {
    throw new CustomException("Failed to obtain requested data.");
    // or: throw new CustomException("Failed to obtain requested data.", ex) ?
  }
}

In this case, I recommend that you not create a "leaky abstraction", where a dependency would be created in a client that would otherwise have no need to know about that third-party library.

Normally, logging and throwing is bad practice, because the same error gets logged repeatedly. But in this case, I think it's justified, since the thrown exception is transported to the client; it may be useful to log it both at the client and server. So the catch block ends up looking like this:

catch (ThirdPartyException ex) {
   String message = "Failed to obtain requested data.";
   log.error(message, ex);
   throw new CustomException(message);
 }

This way, the ThirdPartyException dependency is limited to the server, the server logs contain appropriate implementation-specific information, and the error is correctly reported to the client.

erickson
but that implies that the customexception is also serializable/marshallable, correct? which is the poster's original question.
John Gardner
No, the question states that CustomException is exported, but some exceptions chained to it are not. However, if you use the approach I outline, the client clearly has a dependency on CustomException (it's part of the interface API), and it would have to be available at the client.
erickson
+2  A: 

We capture the message + entire stack trace from the source exception and passed that on as the remote exception's contents. That way you get all of the stack details, but you don't have to worry about any of ANY of the internal exceptions being non serializable.

You never know what other objects might be inside some other third party (or even your own "first party" custom exceptions!)

John Gardner
That is exactly what I did. It works nicely and no dependency problems.
Mario Ortegón