How to avoid exception shadowing?
I suggest you to use try-with-resource-statements introduced in Java 7, in conjunction with the AutoCloseable
-interface.
Sidenote: The
Connection
,Statement
andResultSet
fromjava.sql
all implementAutoCloseable
try (Connection c = DriverManager.getConnection(url)) {
// do your inserts
} catch (Exception e) {
throw new Error("Insert failed", e);
}
This will close your connection
or generally the passed AutoCloseable
appropriately. And will handle the shadowing of the exception by using the Throwable.addSuppressed()
method.
What the equivalent looks like in previous versions can be seen on this other question
Your questions also mentiones a rollback which I haven't covered. This can be done by using the before mentioned Throwable.addSuppressed()
method (as pointed out in the comments by tobias_k), though to be honest it gets quite a bit more messy, and doesn't look as nice anymore:
Exception insertException = null;
try (Connection c = DriverManager.getConnection(url)) {
try {
// do your inserts
} catch (Exception e1) {
insertException = e1;
// do your rollback
}
} catch (Exception e2) {
Error error = new Error("Insert failed", insertException);
error.addSuppressed(e2);
throw error;
}
Just for clarification, the inner catch
-block, can only be reached when the insert fails. Where as the outer catch
can be reached, when any of the following throws an exception:
DriverManager.getConnection()
- Your rollback
Connection.close()
For a small demo you can visit this link, which illustrates how the stacktrace looks like.
What you refer to is called suppressed exceptions in Java.
Starting from Java SE 7 there is a try-with-resources
statement which automatically handles exceptions thrown within it. In your example it can be used like this:
class main
{
public static void main (String[] args)
{
try(Database db = new Database()){ //ex3 can be thrown during closing the resource
try
{
// db.insert ();
throw new Exception ("insert failed");
}
catch (Exception ex1) {
try {
// db.rollback ();
throw new Exception ("rollback failed");
}
catch (Exception ex2) {
throw new Error ("Can not roll back transaction.", ex2);
}
}
}
}
}
In this case, if ex1
and ex3
are thrown, you get ex1
with ex3
in the list of suppressed exceptions.
If ex1
, ex2
and ex3
are thrown, you get ex1
chained with ex2
, and with ex3
in the list of suppressed exceptions.