AWT Exception Handler Cannot Be Reset After Exception

When testing ConcJUnit some more from inside DrJava, I noticed some weird behavior. I had a JUnit 3.8.2 version of a test, and an equivalent JUnit 4 version. Run independently, they behaved as expected (which in my line of work usually means the tests failed), but if I ran them in sequence, then the second test didn’t catch certain errors.

After some experimentation, I found out that it was a problem with the AWT exception handler. The AWT EventDispatchThread class caches the name of the AWT exception handler class the first time an uncaught exception occurs in the event thread; therefore, even when the sun.awt.exception.handler Java property is changed, the same handler will continue to be invoked. Here’s the code from EventDispatchThread:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    private static final String handlerPropName = "sun.awt.exception.handler";
    private static String handlerClassName = null;
    private static String NO_HANDLER = new String();
// ...
    private boolean handleException(Throwable thrown) {

        try {

            if (handlerClassName == NO_HANDLER) {
                return false;   /* Already tried, and failed */
            }

            /* Look up the class name */
            if (handlerClassName == null) {
                handlerClassName = ((String) AccessController.doPrivileged(
                    new GetPropertyAction(handlerPropName)));
                if (handlerClassName == null) {
                    handlerClassName = NO_HANDLER; /* Do not try this again */
                    return false;
                }
            }
// ...

ConcJUnit used different handler classes for JUnit 3-style and 4-style tests, and if a JUnit 3-style test first caused an uncaught exception, a subsequent JUnit 4-style test would not get notified of uncaught exceptions, and vice versa. Now I’m just using one handler, and it “works”.

This still has further implications, though:

  1. If the sun.awt.exception.handler uncaught exception handler property is set and an uncaught exception happens before ConcJUnit can set it, then uncaught exceptions may be missed.
  2. Code that expects to be able to set the sun.awt.exception.handler property cannot be tested correctly with ConcJUnit, because ConcJUnit relies on setting it first.

There are ways around these issues. For example, to circumvent the second problem, ConcJUnit can set the property and immediately cause an uncaught exception in the event thread itself. That way, its own handler is sure to be installed. This handler could then continue to monitor the sun.awt.exception.handler property, and if it changes, delegate to that handler instead of recording an uncaught exception. The first problem isn’t really one if ConcJUnit is used properly.

I won’t implement these improvements, though, unless I notice they are necessary.

This caching behavior, however, showed me two things again: First, it feels like I’m often exploring an artificially complicated problem (Java) space in my research, not something that is intrinsically true. Second, this really is a hack (and Sun says so). I know why Sun implemented the caching, namely to minimize reflection costs, but I don’t think it was done well. Sun really should have cached the class and the class name, and when the class name differs from the Java property, then the class lookup using reflection should have been re-done.

I don’t think this caching behavior is documented anywhere except in the source.

Share

About Mathias

Software development engineer. Principal developer of DrJava. Recent Ph.D. graduate from the Department of Computer Science at Rice University.
This entry was posted in Concurrent Unit Testing, Ramblings, Uncategorized. Bookmark the permalink.

Leave a Reply