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:
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.
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!)
Related
So im reading the below and i understand why you would do it..
https://jenkov.com/tutorials/java-exception-handling/exception-wrapping.html
example :
try{
dao.readPerson();
} catch (SQLException sqlException) {
throw new MyException("error text", sqlException);
}
So what if i want to isolate all external exceptions inside the dao layer only, and only use my exceptions. so in the above example i dont want to send SQLEXception inside the constructor, would doing the below be enough. Would it contain enough information :
throw new MyException("error text", sqlException);
or maybe my constructor should be the following instead
public MyException(String text,Exception ex)
You can inherit your exception from Exception like
MyException extends Exception {
}
and then use try catch like :
try {
dao.readPerson();
} catch (MyException ex) {
// handle Exception
}
by doing this you can do whatever you want in your class and i think its cleaner than other ways.
It will trigger automatically so you dont need to raise an exception.
If you want to catch SQL Exceptions only you can inherit MyException from SqlException so it will only trigger when SqlException happens
I understand that you worry about the catching part of your code knowing about the wrapped exception. In "not knowing" there are different layers.
Level 1: Nothing obligates the catching class to get the cause and therefor explicitly knowing about the SQLException. They just catch the MyException and don't care what's wrapped in it. Usually that's enough.
Level 2. Another level of not knowing is restricting the catching class to even have access to the wrapped exception. In that case why wrap it at all? Just catch the SQLException in your DAO layer and throw MyException without wrapping the original exception in it.
About wrapping the causing Exception instead of the original one. You could do that but you might lose valuable information so 99% of the time it's not recommended. There are some corner cases where I've done it though. Let's say you throwing code runs asynchronously through ExecutorService. Then if an exception is thrown it's wrapped to ExecutionException, but as a caller I might not be interested that the code ran asynchronously so I catch the ExecutionException, get it's cause (the actual exception that happened) and wrap that to my custom exception.
My understanding of these exceptions is if an object in the database that you are looking for doesn't exist or exists these gets thrown? But is it ok for myself to use when I want to handle different cases in MyServiceClass.
Is it bad practice to throw these exceptions or should I create my own Exceptions for let's say if a user dont exist in the database?
How does it work in a real production?
Thanks in advance!
You should only implement a custom exception if it provides a benefit compared to Java's standard exceptions. The class name of your exception should end with Exception.
But it’s sometimes better to catch a standard exception and to wrap it into a custom one. A typical example for such an exception is an application or framework specific business exception. That allows you to add additional information and you can also implement a special handling for your exception class.
When you do that, make sure to set the original exception as the cause. The Exception class provides specific constructor methods that accept a Throwable as a parameter. Otherwise, you lose the stack trace and message of the original exception which will make it difficult to analyze the exceptional event that caused your exception.
public void wrapException(String input) throws MyBusinessException {
try {
// do something
} catch (NumberFormatException e) {
throw new MyBusinessException("A message that describes the error.", e);
}
}
Try not to create new custom exceptions if they do not have useful information for client code.
And if you make a custom exception be sure to:
Document the Exceptions You Specify
Throw Exceptions With Descriptive Messages
Catch the Most Specific Exception First
Don’t Log and Throw
I'm implementing a session bean that throws ApplicationExceptions.
These exceptions have chained stack traces that may contain exceptions whose classes aren't available on the client. Something like:
#Override
public void doSomethingSpecial(MyObject o) throws MyException {
try {
legacySystem.handle(o);
} catch (LegacyException e) {
logger.warn(e.getMessage(), e);
throw new MyException(e);
}
}
Here it's possible that the client gets an exception it doesn't have the class for. This can result in:
Exception in thread "main" java.lang.reflect.UndeclaredThrowableException
at sun.proxy.$Proxy0.doSomethingSpecial(Unknown Source)
at com.myapp.client.Client.main(Client.java:56)
Caused by: java.lang.ClassNotFoundException: MyLegacyException
I don't want the client to know all the possible exceptions that can be thrown on the server side, but having a stack trace is never bad.
How do you handle these problems? Is it a passable solution to implement an Interceptor that decouples the stack trace when the exception is sent back to the client? But then the Interceptor should handle only calls via the RemoteInterface, because internally I'm interested in the whole stack trace.
It depends on your client type. If a client is another team which is developing another component or subsytem, I'm agree with you about:
Having a stack trace is never bad
But if they are customers who have no idea about your application internals, so there is no reason for them to know your exception classes or even see your stack traces. It would be nice to have a protocol which force you to catch all exceptions and wrap them in a high level exception class with a error_code property. This way, you can have a specific error code for each catch statement in your application and you will give your clients a list of these codes.
Anyway, from technical view, if your clients doesn't have access to your internal Exception classes, so they can't have access to your stack trace without referred ClassNotFoundException. If you really want them to see the stack trace, one solution could be to have an Aspect which sits just on the most upper layer of your API (which is going to be called by clients) and catches all the exceptions, writes their stack traces in a String and sends this as a property of the final exception which is going to be caught by caller. This way, the caller can access the stack trace as a formatted String property of the exception.
Edit:
You can even configure your build script, so that this Aspect never be a part of your release versions. So you can give this stack trace messages just in your debug version.
I thought about little roundabout solution, but this is only untested speculation.
You initialize your external exception with internal exception. But if we look at javadoc of Throwable we can see methods get and setStackTrace(StackTraceElement[] stackTrace)
StackTraceElement is initialized with strings. So maybe you can get stack trace from internal exception and set it into your external exception (MyException).
Since RMI settles on Serialization you can use Serialization features to conditionally replace exceptions.
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
public class CarryException extends RuntimeException implements Serializable
{
final String exceptionClass;
public CarryException(Exception cause)
{
super(cause.getMessage());
exceptionClass=cause.getClass().getName();
setStackTrace(cause.getStackTrace());
}
#Override
public String getMessage()
{
// if we get here, reconstructing the original exception did not work
return exceptionClass+": "+super.getMessage();
}
/** Invoked by Serialization to get the real instance */
final Object readResolve() throws ObjectStreamException
{
try
{
Exception ex = Class.forName(exceptionClass).asSubclass(Exception.class)
.getConstructor(String.class).newInstance(super.getMessage());
ex.setStackTrace(getStackTrace());
return ex;
}
catch(InstantiationException|IllegalAccessException|ClassNotFoundException
| IllegalArgumentException|InvocationTargetException|NoSuchMethodException
| SecurityException ex)
{
// can't reconstruct exception on client side
}
return this; // use myself as substitute
}
}
Now you can throw any exception to the client by throw new CarryException(originalException);. The CarryException will always record the stack trace and message of the original exception and recreate the original exception at client side if the class is available. Otherwise the client sees the CarryException so obviously that one exception type must be known on the the client side.
The exception type must have the standard constructor taking a message String for the reconstruction to work. (All other things would be too complicated). But most exception types have that.
There is another catch: replacing via Serialization does only work if Serialization is involved so you must not invoke the methods on the implementation class directly when beeing inside the same JVM. Otherwise you see the CarryException unconditionally. So you have to use a stub even locally, e.g.
((MyRemoteInterface)RemoteObject.toStub(myImplementation)).doSomethingSpecial();
Update
If MyException is known to the client and only LegacyException is not, of course the following works:
catch (LegacyException e) {
logger.warn(e.getMessage(), e);
MyException me=new MyException(e.toString());
me.setStackTrace(e.getStackTrace());
throw me;
}
I have a Java 1.4 web app that uses Hessian to make web service calls. I'm trying to write it as robust and transparent as possible. I don't want any hessian exceptions to make it out of my delegate class when calling the proxy. I want to be able to catch any Hessian runtime exceptions, unwrap them and either rethrow some of the major exceptions (e.g., ConnectException) or rewrap them in another exception. But finding these exceptions are a bit of a challenge.
Every method I have in my delegating class has this sort of structure.
public MyResult myMethod(MyArgsType myArgs)
throws ConnectException
{
try
{
return proxy.myMethod(myArgs);
}
catch (HessianRuntimeException ex)
{
Throwable cause = ex.getCause();
if (cause instanceof ConnectException)
throw (ConnectException)cause;
throw new MyRuntimeException(cause);
}
}
This has been working fine in my own tests but some other runtime exceptions are making it out and I'm missing them. For instance, we recently found that it may throw a HessianConnectionException caused by a SocketException (the remote server was down). I was fully expecting that what I currently have would have caught that. The HessianConnectionException doesn't derive from the HessianRuntimeException so now I have to add that exception to be caught.
public MyResult myMethod(MyArgsType myArgs)
throws SocketException, ConnectException
{
try
{
return proxy.myMethod(myArgs);
}
catch (HessianException ex) // HessianConnectionException derives from HessianException
{
Throwable cause = ex.getCause();
if (cause instanceof SocketException)
throw (SocketException)cause;
throw new MyRuntimeException(cause);
}
catch (HessianRuntimeException ex)
{
Throwable cause = ex.getCause();
if (cause instanceof ConnectException)
throw (ConnectException)cause;
throw new MyRuntimeException(cause);
}
}
Ok that's fine with me, it had to be done... but where does it end? I can't find any documentation on what other runtime exceptions that I need to be aware of or any of their underlying causes.
I'm hoping just catching HessianException and HessianRuntimeException would be enough since those are the only runtime exceptions that I can find listed here. But with these newly found issues, I'm not sure what exceptions I would want to unwrap since it seems like it's a mixed bag (as far as I knew, SocketException and ConnectException were different representations of the same problem).
Is there any documentation in what runtime exceptions are thrown when calling methods through the proxy and all their underlying causes?
I assume you have done web searches etc., so here is a fallback position in case you don't find the documentation you are looking for.
After your existing catches, catch RuntimeException. Test whether the Exception's class name begins with "Hessian" and/or check its package name. If it is not Hessian-originated, rethrow.
After you know it is a Hessian exception you can do something similar to your current strategy, looking through the cause chain for something that makes sense in your context or at least is from a non-Hessian package.
Have this method call:
->
simpleJdbcTemplate.queryForInt(SQL,null);
->
queryForInt() method in the springs SimpleJdbcTemplate throws a DataAccessException which is a runtime exception. I want to propegate exceptions to the view tier of the application since Spring frame work Wraps Checked Exceptions inside RuntimeExceptions I stuck here.
How do I do this?
Explanation 1:
The value-add provided by the Spring Framework's JDBC abstraction framework- they say The Spring Framework takes care of all except 3 and 6. 3 and 6 need to be coded by an application developer
Define connection parameters
Open the connection
Specify the statement
Prepare and execute the statement
Set up the loop to iterate through the results (if any)
Do the work for each iteration
Process any exception
Handle transactions
Close the connection
But if I encounter a situation where the connection to the database losses after certain time the program started. Then a runtime exception will be thrown when a call to the above method made.since I don't handle the exception I cannot inform the user interface (view).
Just because Spring throws a runtime exception doesn't mean you cannot catch it. If you want to do something special for DataAccessExceptions, you can certainly do that:
try {
// query logic
} catch (DataAccessException ex) {
// handle the exception
}
If you're using Spring's MVC framework, it may be worth looking into the ExceptionResolver interface. It's a mechanism for deciding how to handle all those uncaught exceptions thrown by the lower layers of the application. It gives you one last chance to display a different view based on exceptions that are thrown.
It depends if your view tier catches checked exceptions (any subclass of throwable that does not subclass RuntimeException or Error, or are not instances of RuntimeException or Error directly) or unchecked exceptions (RuntimeException or Errors or subclasses of these Throwable subclasses).
Generally, you'll either have something like this:
try {
//... processing
} catch(Exception/RuntimeException e) {
// propagate the exception to the view in a meaningful manner
}
If this is the case, for a runtime exception, you don't have to do anything - the block will catch the runtime exception.
If you want to convert it to checked, assuming you're using a version of Java that supports wrapped exceptions, all you have to do is:
try {
//...spring code
} catch(DataAccessException e) {
throw new Exception(e);
}
Then, your layer above this processing will catch it as a checked exception.
Do you just want to be able to access the original exception information in your View? If so, you should be able to invoke getCause() on the RuntimeException to get the underlying checked Exception that caused it. Otherwise you would need to add a "throws" declaration to your methods that are utilizing SimpleJdbcTemplate, catch DataAccessException and rethrow the checked Exceptions that are wrapped.