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?
Rather than wrapping CustomException in RemoteException, you might modify your remote interface like this:
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.
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:
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.