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 and ResultSet from java.sql all implement AutoCloseable

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.

Tags:

Java

Exception