I am unreasonably fond of Swing. While it has plenty of foibles, and brings a new horror to UIs with Metal, it’s nevertheless quite a nice framework to use – once you’re familiar with it.
The problem is that getting familiar is a path strewn with brambles and holes full on punji sticks. One of the bigger holes is the event dispatch thread (EDT) – everything Swing related should take place on the EDT (even initialisation, under the latest Sun guidelines). When you’re trying to keep the UI fluid it’s all too easy to break the rule – hence, aspects to the rescue!
This topic has been covered by many before, including Alexander Potochkin and Anders Prisak – however, I found their solution needed a little tweaking to be used in our environment. In particular, they had missed two cases we cover – SwingUtilities and SwingWorker.
So, here’s the tweaked aspect. safeMethods now includes a few extras.
package org.infernus.swing.aspects;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import java.awt.*;
@Aspect
public class EDTCheck {
@Pointcut("call (* javax.swing..*+.*(..)) || "
+ "call (javax.swing..*+.new(..))")
public void swingMethods() {
}
@Pointcut("call (* javax.swing..*+.add*Listener(..)) || "
+ "call (* javax.swing..*+.remove*Listener(..)) || "
+ "call (* javax.swing..*+.getListeners(..)) || "
+ "call (* javax.swing..*+.revalidate()) || "
+ "call (* javax.swing..*+.invalidate()) || "
+ "call (* javax.swing..*+.repaint()) || "
+ "target (javax.swing.SwingWorker+) || "
+ "call (* javax.swing.SwingUtilities+.invoke*(..)) || "
+ "call (* javax.swing.SwingUtilities+.isEventDispatchThread()) || "
+ "call (void javax.swing.JComponent+.setText(java.lang.String))")
public void safeMethods() {
}
@Before("swingMethods() && !safeMethods() && !within(EDTCheck)")
public void checkCallingThread(final JoinPoint.StaticPart thisJoinPointStatic) {
if (!EventQueue.isDispatchThread()) {
System.err.println("Swing EDT violation: " + thisJoinPointStatic.getSignature()
+ " (" + thisJoinPointStatic.getSourceLocation() + ")");
Thread.dumpStack();
}
}
}
Once it’s built, we just need to weave it – I’ve already got compile-time weaving configured for Spring @Configurable support, so just add the JAR containing the aspect as a weaveDependency and then the magic happens.
Now, if a Swing call is made off of the EDT, you’ll get complaints:
Swing EDT violation: String javax.swing.JTextArea.getText() (YourSwingClass.java:98)
java.lang.Exception: Stack trace
at java.lang.Thread.dumpStack(Thread.java:1224)
at org.infernus.swing.aspects.EDTCheck.checkCallingThread(EDTCheck.java:55)
... and so on







