Search code examples
javaswingevent-dispatch-thread

Swing verify code on Event Dispatch Thread at runtime


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.


Solution

  • 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.)