Testing Error Handling for Unusual Database Errors

R

Rhino

Have you ever had a piece of database code in which you wanted to test every
probable and improbable error condition that might occur?

For example, suppose you had this code and wanted to make sure that the
error handling did the right thing when an InstantiationException occurred:
----------------------------------------------------------------------------------------------------------------
/* Load the JDBC driver. */
try {
Class.forName(this.jdbcDriverName).newInstance();
}
catch (ClassNotFoundException cnf_excp) {
String msg = "Failed to load JDBC driver " + this.jdbcDriverName
+ ".";
this.logger.logp(Level.SEVERE, this.CLASS_NAME, METHOD_NAME,
msg, cnf_excp);
System.exit(16);
}
catch (InstantiationException i_excp) {
String msg = "Failed to load JDBC driver " + this.jdbcDriverName
+ ".";
this.logger.logp(Level.SEVERE, this.CLASS_NAME, METHOD_NAME,
msg, i_excp);
System.exit(16);
}
catch (IllegalAccessException ia_excp) {
String msg = "Failed to load JDBC driver " + this.jdbcDriverName
+ ".";
this.logger.logp(Level.SEVERE, this.CLASS_NAME, METHOD_NAME,
msg, ia_excp);
System.exit(16);
}

----------------------------------------------------------------------------------------------------------------

Well, up until a few minutes ago, I had always wondered if there was some
simple way to _force_ a desired exception, like an InstantiationException in
this case, to occur at the desired point so that I could make sure the
second catch would work.

Then, inspiration dawned. I tried adding 'throw new
InstantiantionException();' as the last statement in the try block, executed
the code, and BINGO, the InstantiationException occurred. My second catch
block was invoked and did what it was supposed to do.

Well, this is no great miracle by any stretch of the imagination and it
seems blindingly obvious as I mention it now; many of you are probably
yawning as I mention it. Then again, I had wondered for quite some time how
I could make this happen but never quite got around to researching a
solution.

On the theory that others might be in the same position, I thought I'd post
this in case it helps anyone else who has been scratching their heads over
how to do the same thing. Maybe someone will benefit from this note, either
now, or in the future via the newsgroup archive.

By the way, although I've posted this to comp.lang.java.databases, this
technique will work with non-database code too; I just found that the need
for this technique seemed to happen more in database code than in regular
code.

Oh, what the heck, I'm going to crosspost this to comp.lang.java.programmer;
maybe someone there will benefit too :)
 
O

Oliver Wong

Rhino said:
Have you ever had a piece of database code in which you wanted to test
every probable and improbable error condition that might occur?

For example, suppose you had this code and wanted to make sure that the
error handling did the right thing when an InstantiationException
occurred:
/* Load the JDBC driver. */
try {
Class.forName(this.jdbcDriverName).newInstance();
}
catch (ClassNotFoundException cnf_excp) {
String msg = "Failed to load JDBC driver " +
this.jdbcDriverName + ".";
this.logger.logp(Level.SEVERE, this.CLASS_NAME, METHOD_NAME,
msg, cnf_excp);
System.exit(16);
}
catch (InstantiationException i_excp) {
String msg = "Failed to load JDBC driver " +
this.jdbcDriverName + ".";
this.logger.logp(Level.SEVERE, this.CLASS_NAME, METHOD_NAME,
msg, i_excp);
System.exit(16);
}
catch (IllegalAccessException ia_excp) {
String msg = "Failed to load JDBC driver " +
this.jdbcDriverName + ".";
this.logger.logp(Level.SEVERE, this.CLASS_NAME, METHOD_NAME,
msg, ia_excp);
System.exit(16);
}

Assuming that "this.logger" is of type "java.util.logging.Logger", you
might be interested in the method "log", which takes a severity level, a
message, and a throwable. It can infer the class name and the method name.
Example usage:

this.logger.log(Level.SEVERE, msg, ia_excp);

The "problem" with having constants for the class name and method name
is that a maintainer may change the actual method name, but may forget to
change the constant called "METHOD_NAME", and then your logging error
messages will become misleading. Not that this maintainer might not be human
(e.g. the Eclipse refactoring algorithms), so even if you place huge
comments reminding people to rename the constant when they rename the
methods, there is still a chance this step may be "forgotten".
Well, up until a few minutes ago, I had always wondered if there was some
simple way to _force_ a desired exception, like an InstantiationException
in this case, to occur at the desired point so that I could make sure the
second catch would work.

Then, inspiration dawned. I tried adding 'throw new
InstantiantionException();' as the last statement in the try block,
executed the code, and BINGO, the InstantiationException occurred. My
second catch block was invoked and did what it was supposed to do.

Well, this is no great miracle by any stretch of the imagination and it
seems blindingly obvious as I mention it now; many of you are probably
yawning as I mention it. Then again, I had wondered for quite some time
how I could make this happen but never quite got around to researching a
solution.

On the theory that others might be in the same position, I thought I'd
post this in case it helps anyone else who has been scratching their heads
over how to do the same thing. Maybe someone will benefit from this note,
either now, or in the future via the newsgroup archive.

By the way, although I've posted this to comp.lang.java.databases, this
technique will work with non-database code too; I just found that the need
for this technique seemed to happen more in database code than in regular
code.

Oh, what the heck, I'm going to crosspost this to
comp.lang.java.programmer; maybe someone there will benefit too :)

For further reading, see
http://java.sun.com/docs/books/jls/third_edition/html/statements.html#14.20.1

<quote>
If execution of the try block completes abruptly because of a throw of a
value V, then there is a choice:

* If the run-time type of V is assignable to the Parameter of any catch
clause of the try statement, then the first (leftmost) such catch clause is
selected. The value V is assigned to the parameter of the selected catch
clause, and the Block of that catch clause is executed. If that block
completes normally, then the try statement completes normally; if that block
completes abruptly for any reason, then the try statement completes abruptly
for the same reason.
</quote>

In other words, it'll try to use the first catch statement it sees, and if
that catch can't handle the exception, it'll try to use the second one, and
so on.

Also, as an aside, if you use Eclipse as your IDE, it should tell you when
it detects that a certain catch block will never be reached (if, for
example, that exception is never thrown within the try block, or if a
previous catch block will always handle any exception that this catch block
might have handled).

- Oliver
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Staff online

Members online

Forum statistics

Threads
473,764
Messages
2,569,566
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top