Funny Swing EDT problem with exceptions...

I've been posting and describing this problem in a lot of forums now in the last week, and I think that I've gotten pretty good at it, so please bear with me. Whenever I talk about this someone points out an obvious non-problem with this, but after explaining the problem a bit more fully they've always been stumped. Whatever the case is, the behavior observed is at best non-standard and at worst completely wrong.

I'm using NetBeans so if anyone thinks that that might be my problem then please chime in but I don't think that it is.

Open up Netbeans and create a simple little java app. In fact, you could create this:

publicclass Main

{

/** Creates a new instance of Main */

public Main()

{

int[] arr =newint[2];

arr[3] = 0;

}

/**

* @param args the command line arguments

*/

publicstaticvoid main(String[] args)

{

Main m =new Main();

}

}

Now create a new breakpoint. Make it an exception-style breakpoint. Have it break on any uncaught RuntimeExceptions. Debug-run the program. The netbeans debugger will break on the bad array access. As expected.

Now, in netbeans, create a new project again but create it from the GUISampleForm sample code (File->New Project->Samples->General->GUI Form Examples). Open up Antenna.java, and add an actionPerformed event handler to the Ok button (well, you could add it to any button on the form, really, but I like adding it to the Ok button because of the ironic counterpoint, given that everything is clearly NOT ok). Make the event handler look like this:

privatevoid jButton4ActionPerformed(java.awt.event.ActionEvent evt)

{

int[] arr =newint[2];

arr[3] = 0;

}

Again, add the same uncaught RuntimeException breakpoint. Now debug-run the app. What happens?

In the OSX version of Netbeans, nothing will happen. The debugger is silent, and instead of breaking on the obvious runtime exception, something in Swing prints out the stack trace on the console:

Exception in thread"AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 3

at examples.Antenna.jButton4ActionPerformed(Antenna.java:253)

at examples.Antenna.access$000(Antenna.java:4)

at examples.Antenna$1.actionPerformed(Antenna.java:212)

at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1882)

at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2202)

at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:420)

at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:258)

at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:234)

at java.awt.Component.processMouseEvent(Component.java:5554)

at javax.swing.JComponent.processMouseEvent(JComponent.java:3126)

at java.awt.Component.processEvent(Component.java:5319)

at java.awt.Container.processEvent(Container.java:2010)

at java.awt.Component.dispatchEventImpl(Component.java:4021)

at java.awt.Container.dispatchEventImpl(Container.java:2068)

at java.awt.Component.dispatchEvent(Component.java:3869)

at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4256)

at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3936)

at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3866)

at java.awt.Container.dispatchEventImpl(Container.java:2054)

at java.awt.Window.dispatchEventImpl(Window.java:1774)

at java.awt.Component.dispatchEvent(Component.java:3869)

at java.awt.EventQueue.dispatchEvent(EventQueue.java:463)

at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:269)

at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:190)

at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:184)

at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:176)

at java.awt.EventDispatchThread.run(EventDispatchThread.java:110)

In the Windows version of Netbeans, the debugger breaks, but not at the site of the exception (which of course is the expected behavior, and would be awfully useful for examining locals) but instead it breaks on the EventDispatchThread.run() method.

What gives?

I should mention that I'm using the 1.5 JDK...

Message was edited by:

CountSessine

[5328 byte] By [CountSessinea] at [2007-11-27 7:56:51]
# 1

> I've been posting and describing this problem in a lot

> of forums now in the last week, and I think that

> I've gotten pretty good at it...

I beg to differ. If you were really good at it, you wouldn't have framed the question in such a way as to almost guarantee that you'll get no useful answers. I mean, why should we bother answering when we'll probably just be repeating something that was said in one of those many other forums? You don't even say what the "obvious non-problem" is; are you deliberately holding that back so you can say "gotcha!" when someone brings it up here?

I assume you've already tried asking your question over at the Netbeans site, but I suggest you go back and try again. Your problem is with the Netbeans debugger, not with Swing.

uncle_alicea at 2007-7-12 19:38:37 > top of Java-index,Desktop,Core GUI APIs...
# 2

> > I've been posting and describing this problem in a

> lot

> > of forums now in the last week, and I think that

> > I've gotten pretty good at it...

>

> I beg to differ. If you were really good at it, you

> wouldn't have framed the question in such a way as to

> almost guarantee that you'll get no useful answers.

Ah - but you don't know just how bad I was at describing this problem in the first place, do you? I'd describe it in vague terms, and the first batch of responses was always, "it's supposed to work that way." After explaining that, "no, this really isn't the expected behaviour," the next response was, "use Thread.setUnhandledExceptionHandler()," to which I would respond, "as useful as Thread.setUnhandledExceptionHandler() is, that's not really what I want - I want development handling of the exception, i.e. I need the debugger to catch the exception, not deployment handling of the exception, for which Thread.setUnhandledExceptionHandler() would be simply splendid."

Finally, I'd just post some instructions for reproducing the problem which everyone seemed to be more than satisfied with, but no one could really offer any solutions for.

I might have been a bit brusque, but I really thought that everyone would appreciate a quick, concise question with a demonstration that got to the heart of the issue immediately.

> I mean, why should we bother answering when we'll

> probably just be repeating something that was said

> in one of those many other forums?

Because handling exceptions in a non-thread-safe UI toolkit is an interesting problem? Intellectual interest? In any case, here are the two instances that I have my forum passwords for here at work:

http://episteme.arstechnica.com/eve/forums/a/tpc/f/6330927813/m/913005545831?r=913005545831#913005545831

http://forums.java.net/jive/thread.jspa?threadID=27526&tstart=0

> You don't even

> say what the "obvious non-problem" is; are you

> deliberately holding that back so you can say

> "gotcha!" when someone brings it up here?

Haha! Believe me, there are no mousetraps here. Just me, scratching my head.

> I assume you've already tried asking your question

> over at the Netbeans site, but I suggest you go back

> and try again. Your problem is with the Netbeans

> debugger, not with Swing.

Welcome to you, too.

At any rate, I'll ask my question there too, but having worked on a niche-debugger and having some knowledge about how you actually implement breakpoints on exceptions (although I'll admit that I've never had to do it in java), I don't think this has anything to Netbeans. I think it has a lot more to do with that big try-catch block in EventDispatchThread.run(). How is a debugger is supposed to catch an uncaught exception when all exceptions are caught...?

Message was edited by:

CountSessine

The format was letterboxed to fit on your television screen, and scenes were editted for violent and sexual content.

Message was edited by:

CountSessine

CountSessinea at 2007-7-12 19:38:37 > top of Java-index,Desktop,Core GUI APIs...
# 3

> but I really thought that everyone would appreciate a quick, concise

> question with a demonstration that got to the heart of the issue immediately.

Yep, thats what we like, problem is you question didn't meet your own requirements.

You didn't provide any demonstration. If you want us to test some code then post the code, the whole simple demo program. If its not a NetBeans problem, then people who use other IDE should be able to run the demo code and encounter the same problems. But unless you post executable code we will never be able to exactly duplicate the problem.

If you need further help then you need to create a [url http://homepage1.nifty.com/algafield/sscce.html]Short, Self Contained, Compilable and Executable, Example Program[/url] (SSCCE) that demonstrates the incorrect behaviour, because I can't guess exactly what you are doing based on the information provided.

Don't forget to use the [url http://forum.java.sun.com/help.jspa?sec=formatting]Code Formatting Tags[/url] so the posted code retains its original formatting.

camickra at 2007-7-12 19:38:37 > top of Java-index,Desktop,Core GUI APIs...
# 4

I don't see how it's a Swing EDT problem. NetBeans debugger has different behaviour under different OSes and project types, so that makes it a NetBeans problem. Or maybe a JDK problem, since the implementation on Windows is from Sun and on Mac is from Apple. So, internally, the uncaught exceptions on EDT might be handled differently by different VMs - once again, this is not a Swing problem per se.

And what's so funny about it?

kirillga at 2007-7-12 19:38:37 > top of Java-index,Desktop,Core GUI APIs...
# 5
So you haven't already posted your question at the Netbeans site? It wasn't the first place you tried? I think you still have considerable room for improvement at this question-asking stuff. ^_^
uncle_alicea at 2007-7-12 19:38:37 > top of Java-index,Desktop,Core GUI APIs...
# 6

> I don't see how it's a Swing EDT problem. NetBeans

> debugger has different behaviour under different OSes

> and project types, so that makes it a NetBeans

> problem. Or maybe a JDK problem, since the

> implementation on Windows is from Sun and on Mac is

> from Apple. So, internally, the uncaught exceptions

> on EDT might be handled differently by different VMs

> - once again, this is not a Swing problem per se.

Exactly the same thing happens in jdb, the command-line debugger. The exception is caught in EventDispatchThread.run(), not at the site of the exception.

C:\repositories\main\netbeans workspace\Antenna\build\classes>jdb Antenna

Initializing jdb ...

> catch uncaught java.lang.RuntimeException

Deferring uncaught java.lang.RuntimeException.

It will be set after the class is loaded.

> run

run Antenna

Set uncaught java.lang.Throwable

Set deferred uncaught java.lang.RuntimeException

Set deferred uncaught java.lang.Throwable

>

VM Started:

I push the Ok button here...

Exception occurred: java.lang.ArrayIndexOutOfBoundsException (uncaught)

Exception occurred: java.lang.ArrayIndexOutOfBoundsException (uncaught)"thread=AWT-EventQueue-0", java.awt.EventDispatch

Thread.run(), line=144 bci=152

AWT-EventQueue-0[1] where

[1] java.awt.EventDispatchThread.run (EventDispatchThread.java:144)

AWT-EventQueue-0[1]

And it's a similar story on OSX - it doesn't even break when I generate the exception - it just prints out the stack trace on the console and continues execution.

Message was edited by:

CountSessine

Added the addendum about OSX.

CountSessinea at 2007-7-12 19:38:37 > top of Java-index,Desktop,Core GUI APIs...
# 7

> > but I really thought that everyone would appreciate

> a quick, concise

> > question with a demonstration that got to the heart

> of the issue immediately.

>

> Yep, thats what we like, problem is you question

> didn't meet your own requirements.

>

> You didn't provide any demonstration. If you want us

> to test some code then post the code, the whole

> simple demo program. If its not a NetBeans problem,

> then people who use other IDE should be able to run

> the demo code and encounter the same problems. But

> unless you post executable code we will never be able

> to exactly duplicate the problem.

I did provide a demo, but it was indeed very Netbeans-centric.

> If you need further help then you need to create a

> [url

> http://homepage1.nifty.com/algafield/sscce.html]Short,

> Self Contained, Compilable and Executable, Example

> Program[/url] (SSCCE) that demonstrates the incorrect

> behaviour, because I can't guess exactly what you are

> doing based on the information provided.

>

> Don't forget to use the [url

> http://forum.java.sun.com/help.jspa?sec=formatting]Cod

> e Formatting Tags[/url] so the posted code retains

> its original formatting.

I'll put this together tonight. Thanks camickr...

CountSessinea at 2007-7-12 19:38:38 > top of Java-index,Desktop,Core GUI APIs...
# 8

> If you need further help then you need to create a

> [url

> http://homepage1.nifty.com/algafield/sscce.html]Short,

> Self Contained, Compilable and Executable, Example

> Program[/url] (SSCCE) that demonstrates the incorrect

> behaviour, because I can't guess exactly what you are

> doing based on the information provided.

>

> Don't forget to use the [url

> http://forum.java.sun.com/help.jspa?sec=formatting]Cod

> e Formatting Tags[/url] so the posted code retains

> its original formatting.

Now that I've pulled all of the Matisse GroupLayout stuff out, it's much shorter. Here it is. Super-ridiculously simple.

import java.awt.FlowLayout;

public class Antenna extends javax.swing.JFrame {

/** Creates new form Antenna */

public Antenna()

{

okButton = new javax.swing.JButton();

setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

setTitle("Antenna");

okButton.setText("OK");

okButton.addActionListener(new java.awt.event.ActionListener()

{

public void actionPerformed(java.awt.event.ActionEvent evt)

{

okButtonActionPerformed(evt);

}

});

FlowLayout layout = new FlowLayout();

layout.setAlignment(FlowLayout.LEFT);

setLayout(layout);

add(okButton);

pack();

}

private void okButtonActionPerformed(java.awt.event.ActionEvent evt)

{

int arr[] = new int[2];

arr[3] = 0;

}

/**

* @param args the command line arguments

*/

public static void main(String args[]) {

java.awt.EventQueue.invokeLater(new Runnable() {

public void run() {

new Antenna().setVisible(true);

}

});

}

private javax.swing.JButton okButton;

}

As I said, this is something that anyone who's run off the end of an array or used a null pointer or whatever in an event callback will have run into.

Message was edited by:

CountSessine

CountSessinea at 2007-7-12 19:38:38 > top of Java-index,Desktop,Core GUI APIs...
# 9

Works this way in eclipse too. I believe you are boned. To repeat what others

have told you, that is how it appears that it is supposed to work. Quoting,

When running under jdb, however, control returns to jdb at the offending throw.

Control doesn't return to where the exception is created, it is where it is

thrown. In the case of the EDT, that is from processException. The next

instruction to be executed is in the finally block of EDT's run(), so that's

where you end up in the debugger. The location where the exception is

created has been unwound off the stack.

As to why you don't break at all under OSX, I tend to think it is indeed due to

differences in the JVM. Thread.dispatchUncaughtException notes that it is

intended to be called only by the JVM, and it is certainly encountered in this

flow, so perhaps the JVM on OSX just does things differently.

I think the only approach that will come close for your purposes is to set

breakpoints in the constructors of RuntimeException. To really meet your

needs, though, these would need to be conditional breakpoints that looked

down the stack to see if they are being invoked explicitly by the code, or

implicitly by the JVM, and I don't know if that's doable.

JayDSa at 2007-7-12 19:38:38 > top of Java-index,Desktop,Core GUI APIs...
# 10

> Works this way in eclipse too. I believe you are

> boned.

Yeah, that's what I figured.

> To repeat what others

> have told you, that is how it appears that it is

> supposed to work. Quoting,

> When running under jdb, however, control returns

> to jdb at the offending throw.

> Control doesn't return to where the exception is

> created, it is where it is

> thrown. In the case of the EDT, that is from

> processException. The next

> instruction to be executed is in the finally block of

> EDT's run(), so that's

> where you end up in the debugger. The location where

> the exception is

> created has been unwound off the stack.

Exactly. I don't really want this to behave any differently than you describe, though. I'm really just more curious about that code in EventDispatchThread.run(). Why does it catch all Throwables? If that one chunk of code were excised, I believe this would work in the expected way.

I guess what I was really looking for, posting here, was a justification for that catch (Throwable) block. It seems like at the very least there should be a check for a system variable to turn that behaviour off. I was hoping that one of the Swing engineers might read my post and say, "Yes, we didn't want to put that there, but turning it off wouldn't get you anywhere because..." It would make the annoying behavior a bit less annoying.

> As to why you don't break at all under OSX, I tend to

> think it is indeed due to

> differences in the JVM.

> Thread.dispatchUncaughtException notes that it is

> intended to be called only by the JVM, and it is

> certainly encountered in this

> flow, so perhaps the JVM on OSX just does things

> differently.

That's more or less what I was thinking. I'm not bothered by the different OSX behavior, really. Neither of them behave 'correctly'.

> I think the only approach that will come close for

> your purposes is to set

> breakpoints in the constructors of RuntimeException.

> To really meet your

> needs, though, these would need to be conditional

> breakpoints that looked

> down the stack to see if they are being invoked

> explicitly by the code, or

> implicitly by the JVM, and I don't know if that's

> doable.

Thanks - but I think I'll probably just live with it the way it is.

CountSessinea at 2007-7-12 19:38:38 > top of Java-index,Desktop,Core GUI APIs...