tags:

views:

158

answers:

3

Are there any libraries that instrument code to verify that methods called on swing components are called on the event dispatch thread? It probably wouldn't be too difficult to write some basic code for doing this, but I'm sure there are edge cases and whatnot that other people have handled. I'm looking for this at runtime though, not for unit tests.

thanks, Jeff

A: 

All you need is the following code:

void method() {
    if (!SwingUtilities.isEventDispatchThread()) {
       SwingUtilities.invokeAndWait(new Runnable() { public void run() { method(); } );
       return;
    }

    // do method code here, guaranteed to be in EDT
}

Also, using Substance as your LAF will help you to work out where Swing-related stuff isn't being executed on the EDT. It has checks in place to make sure that any Swing stuff is done on the proper thread, or it fails with an exception.

Chris Dennett
"instrument code" indicates that he wants to do this compile time, not runtime.
aioobe
Ergh. Be clear whether you are on the EDT or not. Code should not check and then do an `invokeLater`. Certainly avoid `invokeAndWait` if you don't like deadlocks. `assert java.awt.EventQueue.isDispatchThread();` - done.
Tom Hawtin - tackline
@aioobe dunno, he says 'instrument', and then goes on to say that he wants it at runtime. I suppose he's looking for annotations which decorate the code to check the thread safeness. Ardor3D does something similar with the @mainthread annotation.
Chris Dennett
Ah, ok, I see. Thx.
aioobe
I'm basically trying to test my existing app. There have been a few developers on it and I just want to run it and make sure the Swing stuff is happening on the EDT without manually plowing through all the code. I don't care if it's with aspects or annotations ,just seeing if something existed already.
Jeff Storey
Use the Substance LAF as mentioned. It'll throw up exceptions. I've used this tactic in the past.http://www.pushing-pixels.org/?p=368
Chris Dennett
A: 

From a coding point of view, clearly separate EDT code from non-EDT code. Avoid SwingWorker like the plague.

To assert that you are on the EDT (insert ! for off), add the line:

assert java.awt.EventuQueue.isDispatchThread();

You will need -ea/-enableassertions for this to do anything. However, it mostly works as an executable comment.

Tom Hawtin - tackline
What's your alternative for long running tasks instead of SwingWorker?
Jeff Storey
Sent tasks to another thread [pool], which sends tasks back (directly or indirectly) through `invokeLater`.
Tom Hawtin - tackline
+3  A: 

The FEST framework has a tool to detect Swing usage off the EDT. It's basically a RepaintManager that you install. The framework is oriented towards testing, but the RepaintManager can be used at deployment time.

Alternatively, to check all methods such as getters and setters for access only on the EDT, you can use AspectJ and load-time weaving to add the SwingUtilities.isDisaptchThread() advice to each method on your swing components (and the JDK Swing components.)

@Aspect
public class EDTCheck {

    @Pointcut("call (* javax.swing..*+.*(..)) || " +
              "call (javax.swing..*+.new(..))")
    public void swingMethods() {}

    @Pointcut("call (* com.mystuff.swing..*+.*(..)) || " +
              "call (com.mystuff.swing..*+.new(..))")
    public void mySwingMethods() {}


    @Pointcut("call (* javax.swing..*+.add*Listener(..)) || " +
              "call (* javax.swing..*+.remove*Listener(..)) || " +
              "call (void javax.swing.JComponent+.setText(java.lang.String))")
    public void safeMethods() {}

    @Before("(swingMethods() || mySwingMethods()) && !safeMethods()")
    public void checkCallingThread(JoinPoint.StaticPart thisJoinPointStatic) {
        if(!SwingUtilities.isDispatchThread()) {
            System.out.println(
                    "Swing single thread rule violation: " 
                    + thisJoinPointStatic);
            Thread.dumpStack();
            // or you might throw an unchecked exception
        }
    }

}

(Slightly modified from the article - added mySwingMethods pointcut, and use SwingUtiliites.isDispatchThread(). In practice it is the same as EventQueue.isDispatchThread() but the abstraction is cleaner.)

mdma
Thanks. I had seen FEST but saw it only in a unit testing context. Guess I could use it outside.
Jeff Storey