The Source for Java Technology Collaboration
User: Password:



Alexander Potochkin

Alexander Potochkin's Blog

Debugging Swing, the final summary

Posted by alexfromsun on February 16, 2006 at 11:49 AM | Comments (39)

It's taken some time to study all possible ways of detecting Event Dispatch Thread rule violations,
and now I feel I this topic is about to be closed.

But let me tell from the beginning:

ThreadCheckingRepaintManager

I was really surprised when I got to know about the smart solution invented by Scott Delap
who created a RepaintManager which finds EDT mistakes, I started to play with it and noticed that


Note: Please take the latest version of the ThreadCheckingRepaintManager from the SwingHelper project

This solution has the following advantages:

  1. It definitely helps in finding EDT problems
  2. You can use it right now, no third-party libs are required
  3. It is simple and elegant

But from the other side I thought about the following problems

  1. repaint() method is thread-safe and it is not a mistake to invoke it out of EDT
  2. There are a lot of methods in Swing which don't produce repaint events, the most obvious example is getters.
    If you call e.g. JTextField.setText() from EDT and the same time JTextField.getText() from another thread the result is unpredictable

The first problem is easy to solve:
to skip repaint() invocations the stack trace can be checked, I ended up with the following code:

public class CheckThreadViolationRepaintManager extends RepaintManager {
    // it is recommended to pass the complete check  
    private boolean completeCheck = true;

    public boolean isCompleteCheck() {
        return completeCheck;
    }

    public void setCompleteCheck(boolean completeCheck) {
        this.completeCheck = completeCheck;
    }

    public synchronized void addInvalidComponent(JComponent component) {
        checkThreadViolations(component);
        super.addInvalidComponent(component);
    }

    public void addDirtyRegion(JComponent component, int x, int y, int w, int h) {
        checkThreadViolations(component);
        super.addDirtyRegion(component, x, y, w, h);
    }

    private void checkThreadViolations(JComponent c) {
        if (!SwingUtilities.isEventDispatchThread() && (completeCheck || c.isShowing())) {
            Exception exception = new Exception();
            boolean repaint = false;
            boolean fromSwing = false;
            StackTraceElement[] stackTrace = exception.getStackTrace();
            for (StackTraceElement st : stackTrace) {
                if (repaint && st.getClassName().startsWith("javax.swing.")) {
                    fromSwing = true;
                }
                if ("repaint".equals(st.getMethodName())) {
                    repaint = true;
                }
            }
            if (repaint && !fromSwing) {
                //no problems here, since repaint() is thread safe
                return;
            }
            exception.printStackTrace();
        }
    }
}

Some comments about the code:

Initially there was a rule that it is safe to create and use Swing components until they are realized
but this rule is not valid any more, and now it is recommended to interact with Swing from EDT only

That's why completeCheck flag is used - if you test the old program switch it to false,
but new applications should be tested with completeCheck set to true

By the way, there is a chance that an application already uses a custom RepaintManager,
so it would be better to be able to "wrap" a custom RepaintManager to support existing functionality

public class CheckThreadViolationRepaintManager extends RepaintManager {
    private final RepaintManager delegatee;

    public CheckThreadViolationRepaintManager() {
        this(new RepaintManager());
    }

    public CheckThreadViolationRepaintManager(RepaintManager delegatee) {
        if (delegatee == null || delegatee instanceof CheckThreadViolationRepaintManager) {
            throw new IllegalArgumentException();
        }
        this.delegatee = delegatee;
    }

    public synchronized void addInvalidComponent(JComponent component) {
        checkThreadViolations(component);
        // use delegatee instead of super for *all* methods
        delegatee.addInvalidComponent(component);
    }
    
    //other methods skipped

}

Visit the Scott Delap's blog where you can find all information about this technique

CheckThreadViolationRepaintManager is really useful and can detect a lot of EDT mistakes, but... not all of them
As I said above if methods doesn't send repaint events, RepaintManager doesn't work for it

That's why I continued finding the complete solution

My first intention was to find a solution which can easily detect EDT violations and which doesn't need any third party tools or libraries (like CheckThreadViolationRepaintManager works) and that explains my next try:

JVMTI agent

Thanks to Stepan Rutz I got an example of JVMTI which can detect EDT problems via bytecode instrumentation,
the agent can instrument classes from javax.swing package and insert required checking to the beginning of any methods in runtime.

Stepan, I didn't post your code here since I don't have your permission, could you publish a link to the code you sent me ?

I started to work with it and realized this solution has some drawbacks

  1. It is not a pure java solution, using JNI to invoke java methods from C code is not as clear as that
  2. Since JVMTI agent uses native code it requires to be compiled for each platform differently

Hence I switched to java.lang.instrument package which allows to create agents without C coding

Anyway it was a interesting experience, and I realized that JVMTI is very powerful and you can get a lot of specific information from JVM e.g. garbage collection or object allocations events tracking

java.lang.instrument.ClassFileTransformer

ClassFileTransformer has the only method, it takes the class and returns modified bytecode,
sounds pretty simple but to use it you need to know the format of java bytecode very well

Fortunately I found the BCEL library which simplifies bytecode transformations and when I started reading manuals
the AWT lead Oleg Sukhodolsky came to see me and I told him about my current task.

He just smiled and the next day I got email from him with the java agent which inserts

if (!java.awt.EventQueue.isDispatchThread()) {
    Thread.dumpStack();
} 

to the beginning of each method which name start with "set" or "get" for selected classes in javax.swing package

Binary and source code of the agent is here

To compile and run it you need another bytecode manipulation tool the ASM framework

But wait, if I tried ASM framework, why shouldn't I tried AOP,
which is known as a suitable tool for advanced logging of existing applications?

AspectJ

I downloaded AspectJ, spent one evening and voila:

import javax.swing.*;

aspect EdtRuleChecker {
    private boolean isStressChecking = true;
    
    public pointcut anySwingMethods(JComponent c):
         target(c) && call(* *(..));

    public pointcut threadSafeMethods():         
         call(* repaint(..)) || 
         call(* revalidate()) ||
         call(* invalidate()) ||
         call(* getListeners(..)) ||
         call(* add*Listener(..)) ||
         call(* remove*Listener(..));

    //calls of any JComponent method, including subclasses
    before(JComponent c): anySwingMethods(c) && 
                          !threadSafeMethods() &&
                          !within(EdtRuleChecker) {
     if(!SwingUtilities.isEventDispatchThread() &&
         (isStressChecking || c.isShowing())) 
     {
             System.err.println(thisJoinPoint.getSourceLocation());
             System.err.println(thisJoinPoint.getSignature());
             System.err.println();
      }
    }

    //calls of any JComponent constructor, including subclasses
    before(): call(JComponent+.new(..)) {
      if (isStressChecking && !SwingUtilities.isEventDispatchThread()) {
          System.err.println(thisJoinPoint.getSourceLocation());
          System.err.println(thisJoinPoint.getSignature() +
                                " *constructor*");
          System.err.println();
      }
    }
}

This aspect detects all EDT rule violations in your Swing code and has the only drawback -
to run it you need to download an additional jar file

Conclusion

We are going to make Swing debugging easier in Java 1.7
but good news that it is possible to detect Event Dispatch Thread rule violations in your Swing code right now.

ThreadCheckingRepaintManager can find a lot of problematic methods invocations,
but if you want to be absolutely sure - make your own java agent or simply use aspects.


Bookmark blog post: del.icio.us del.icio.us Digg Digg DZone DZone Furl Furl Reddit Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment

  • Might I suggest creating a Java.net project for checking Swing threading with tools using each of the techniques you mention. It would also provide a central place for ThreadCheckingRepaintManager additions/fixes. I'm happy to donate my code as a starting point.

    Posted by: scottdelap on February 16, 2006 at 02:57 PM

  • Hello Scott

    Thank you for your support

    I created the swinghelper java.net project
    https://swinghelper.dev.java.net/

    It is pending approval, I'll let you know when it is approved and work begins

    Thanks
    Alex

    Posted by: alexfromsun on February 17, 2006 at 02:07 AM

  • "Debugging Swing, the final summary" sounds a lot like "The Last Word in Swing Threads". Have we learned nothing from Sean Connery?

    As Ben Galbraith demonstrates so clearly here (sorry, members only), you must also not block the EDT.

    Here's a technique for debugging that problem.

    Blocking the EDT for long enough that the application seems sluggish is probably a much more common problem than actually producing a deadlock.

    Posted by: coxcu on February 17, 2006 at 07:14 AM

  • Hi Alex,

    this is Stepan Rutz writing. Please go ahead and do whatever you want with the jvmi related code i send you. I thought i had enclosed a reference to the WTFPL licence. Its just a the code from a night of playing-around. Please consider that code to be released under the WTFPL licence. Basically WTFPL means free as in really free. http://sam.zoy.org/wtfpl/

    Thanks for hearing my suggestions. And i agree with your thoughts. A java-based instrumentation is certainly cleaner and nicer to maintain.

    Regards from stormy cologne.
    Stepan

    Posted by: roots on February 17, 2006 at 07:34 AM

  • Alex, "Don't block the EDT" is one of my Event Dispatch Thread rules.

    Thanks for doing all of this work to help stamp out EDT problems. Will the new project try to help with both problems?

    Posted by: coxcu on February 17, 2006 at 07:59 AM

  • Hi coxcu

    You are absolutely right -
    "Don't block Edt" is definitely one the main rules

    That project is supposed to collect all Swing related debugging techniques, and detecting EDT blocking is definitely one ot them
    The blog's title might be a bit misleading, sorry

    I named it because of two previous blogs

    Alex

    Posted by: alexfromsun on February 17, 2006 at 08:10 AM

  • Another useful tool when finding EDT hang-ups in applications is to find out where in the code long running tasks are executed on the EDT instead of a separate Thread.

    link

    This debug solution makes finding those tasks a one liner,
    main(){
    EventDispatchThreadHangMonitor.initMonitoring();
    ...
    }


    then check for exceptions being printed.

    The code referenced is GPL and the jar file can be found at link

    Posted by: jorgenrapp on February 17, 2006 at 12:39 PM

  • Can you use AspectJ with the javac compiler?
    or does it still needs it own compiler. (That would be the showstopper for me)

    Kees.

    Posted by: keeskuip on February 17, 2006 at 03:56 PM

  • Hello keeskuip

    You definitely need their compiler to compile aspects and their java runner to run your application with compiled aspects.
    But you don't need to recompile your applications if you want to try it.
    So, check it out !

    Alex

    Posted by: alexfromsun on February 19, 2006 at 05:49 AM


  • Alex,

    At the beginning of this blog you say that:
    "If you call e.g. JTextField.setText() from EDT and the same time JTextField.getText() from another thread the result is unpredictable "

    On the other hand JavaDoc for JTextComponent.setText method says: "This method is thread safe, although most Swing methods are not".


    Is here or there any mistake?

    Thanks,

    Maxim

    Posted by: maxz1 on February 23, 2006 at 08:08 AM

  • Hello Maxim

    Javadoc clearly declared JTextField.setText() as a thread safe
    that's correct, but JTextField.getText() is not thread safe
    So when you invoke getText() from the wrong thread you may get
    an unpredictable result

    Alex

    Posted by: alexfromsun on February 28, 2006 at 02:09 AM

  • Hi Alexander,

    I've been using your repaint manager and it's been very helpful -- thanks!

    I wanted to amend the utility to handle the thread-safe call of JTextComponent.setText in addition to repaint. I propose a change like the following:

    boolean threadSafeMethod = false;
    boolean fromSwing = false;
    StackTraceElement[] stackTrace = new Exception().getStackTrace();
    for (int i = 0; i < stackTrace.length; i++)
    {
    if (threadSafeMethod && stackTrace[i].getClassName().startsWith("javax.swing."))
    {
    fromSwing = true;
    }
    if ("repaint".equals(stackTrace[i].getMethodName())
    || "setText".equals(stackTrace[i].getMethodName()))
    {
    threadSafeMethod = true;
    fromSwing = false;
    }
    }

    if (threadSafeMethod && !fromSwing)
    {
    // Calling a thread safe method; no problem
    return;
    }

    What do you think?

    Posted by: jaredmac on August 18, 2006 at 08:54 AM

  • Hello jaredmac

    I looked to JTextComponents' methods which marked as thread safe,
    and changed my mind, I suppose they are not really thread safe

    Just have a look to JTextComponent.setText() for example
    I do think if I setText() e.g. from main thread and getText() from EDT
    I will likely have problems

    I am going to file a bug to update javadoc

    Thanks
    alexp

    Posted by: alexfromsun on August 23, 2006 at 08:07 AM

  • So does this exception report indicate an error in my code or within swing? PageLoader seems to be a Thread, so looks like Swing is not following the rules, perhaps this is another example where this is OK?


    java.lang.Exception
    at CheckThreadViolationRepaintManager.checkThreadViolations(CheckThreadViolationRepaintManager.java:43)
    at CheckThreadViolationRepaintManager.addDirtyRegion(CheckThreadViolationRepaintManager.java:37)
    at javax.swing.JComponent.repaint(JComponent.java:4518)
    at java.awt.Component.repaint(Component.java:2774)
    at javax.swing.text.FlowView$FlowStrategy.removeUpdate(FlowView.java:353)
    at javax.swing.text.FlowView.removeUpdate(FlowView.java:253)
    at javax.swing.text.View.forwardUpdateToView(View.java:1219)
    at javax.swing.text.View.forwardUpdate(View.java:1192)
    at javax.swing.text.BoxView.forwardUpdate(BoxView.java:222)
    at javax.swing.text.View.removeUpdate(View.java:757)
    at javax.swing.text.View.forwardUpdateToView(View.java:1219)
    at javax.swing.text.View.forwardUpdate(View.java:1192)
    at javax.swing.text.BoxView.forwardUpdate(BoxView.java:222)
    at javax.swing.text.View.removeUpdate(View.java:757)
    at javax.swing.plaf.basic.BasicTextUI$RootView.removeUpdate(BasicTextUI.java:1520)
    at javax.swing.plaf.basic.BasicTextUI$UpdateHandler.removeUpdate(BasicTextUI.java:1764)
    at javax.swing.text.AbstractDocument.fireRemoveUpdate(AbstractDocument.java:242)
    at javax.swing.text.html.HTMLDocument.access$500(HTMLDocument.java:74)
    at javax.swing.text.html.HTMLDocument$HTMLReader.adjustEndElement(HTMLDocument.java:2061)
    at javax.swing.text.html.HTMLDocument$HTMLReader.flush(HTMLDocument.java:2100)
    at javax.swing.text.html.HTMLEditorKit.read(HTMLEditorKit.java:231)
    at javax.swing.JEditorPane.read(JEditorPane.java:519)
    at javax.swing.JEditorPane.read(JEditorPane.java:537)
    at javax.swing.JEditorPane$PageLoader.run(JEditorPane.java:566)

    Posted by: johnpm on November 27, 2006 at 01:08 AM

  • Hello johnpm
    It is very interesting
    Could you publish the test case which gives that stacktrace ?
    Thanks
    alexp

    Posted by: alexfromsun on November 27, 2006 at 02:27 AM

  • Here you go, seems to do the trick:


    /**
    * EditorPaneEDTViolation.java
    * Created on 28 November 2006, 17:10
    **/
    import java.awt.BorderLayout;
    import java.awt.EventQueue;
    import java.io.IOException;
    import java.net.URL;
    import javax.swing.BoxLayout;
    import javax.swing.JComponent;
    import javax.swing.JEditorPane;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.RepaintManager;
    import javax.swing.SwingUtilities;

    /** @author JohnM */

    public class EditorPaneEDTViolation extends JFrame{
    static JEditorPane msgArea;

    public EditorPaneEDTViolation() {
    setTitle("EDT Violations R Us");
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setLayout(new BorderLayout());

    msgArea = new JEditorPane();
    JPanel p = new JPanel();
    p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
    p.add(msgArea);
    add(p, BorderLayout.CENTER);

    setBounds(100, 100, 800, 600);
    }

    public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable(){
    public void run(){
    RepaintManager.setCurrentManager(new CheckThreadViolationRepaintManager());
    final EditorPaneEDTViolation epv = new EditorPaneEDTViolation();
    epv.setVisible(true);
    try {
    msgArea.setPage(new URL("http://www.google.com"));
    } catch (IOException ex) {
    ex.printStackTrace();
    }
    }
    });
    }

    static class CheckThreadViolationRepaintManager extends RepaintManager {
    // it is recommended to pass the complete check
    private boolean completeCheck = true;

    public boolean isCompleteCheck() {
    return completeCheck;
    }

    public void setCompleteCheck(boolean completeCheck) {
    this.completeCheck = completeCheck;
    }

    public synchronized void addInvalidComponent(JComponent component) {
    checkThreadViolations(component);
    super.addInvalidComponent(component);
    }

    public void addDirtyRegion(JComponent component, int x, int y, int w, int h) {
    checkThreadViolations(component);
    super.addDirtyRegion(component, x, y, w, h);
    }

    private void checkThreadViolations(JComponent c) {
    if (!SwingUtilities.isEventDispatchThread() && (completeCheck || c.isShowing())) {
    Exception exception = new Exception();
    boolean repaint = false;
    boolean fromSwing = false;
    StackTraceElement[] stackTrace = exception.getStackTrace();
    for (StackTraceElement st : stackTrace) {
    if (repaint && st.getClassName().startsWith("javax.swing.")) {
    fromSwing = true;
    }
    if ("repaint".equals(st.getMethodName())) {
    repaint = true;
    }
    }
    if (repaint && !fromSwing) {
    //no problems here, since repaint() is thread safe
    return;
    }
    exception.printStackTrace();
    }
    }
    }
    }

    Posted by: johnpm on November 28, 2006 at 09:36 AM

  • Hello John

    Well done !
    you have found a problem in the text package
    We should fire all notfications on EDT,
    but your test case reveals the problem

    I just filed a bug #6502558
    (it takes some time for it to get visible)

    Thank you John
    you helped us to make Swing better !
    alexp

    Posted by: alexfromsun on December 08, 2006 at 10:33 AM

  • Alex, the following test case demonstrates an EDT violation by calling #repaint(Rectangle r). Because repaints are thread safe I'm wondering if this is really an EDT violation.


    public class RepaintEDTViolationDemo extends JFrame
    {
    public static void main(String[] args) throws Exception
    {
    SwingUtilities.invokeLater(new Runnable()
    {
    public void run()
    {
    RepaintManager.setCurrentManager(new CheckThreadViolationRepaintManager(true));
    new RepaintEDTViolationDemo();
    }
    });
    }

    public RepaintEDTViolationDemo()
    {
    super();
    add(new JButton(new StartAction("Start")), BorderLayout.NORTH);

    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setSize(300, 200);
    setLocationRelativeTo(null);
    setVisible(true);
    }

    static class StartAction extends AbstractAction
    {
    public StartAction(String name)
    {
    super(name);
    }

    public void actionPerformed(ActionEvent evt)
    {
    final JButton button = (JButton)evt.getSource();
    new Thread()
    {
    public void run()
    {
    Rectangle rect = button.getBounds();

    //causes EDT thread violation
    button.repaint(rect);

    //works fine
    //button.repaint(0, rect.x, rect.y, rect.width, rect.height);
    }
    }.start();
    }
    }

    }


    -Wolfgang

    Posted by: wzberger on July 14, 2007 at 06:22 AM

  • Hello Wolfgang

    Thanks for fiding this problem !
    I just fixed it and updated the sources on SwingHelper

    Your comments are welcome
    Thanks again
    alexp

    Posted by: alexfromsun on July 17, 2007 at 02:49 AM

  • This is really nice. It found a problem in my code in about 2 minutes - one that I didn't know I had.

    However, I am seeing an error condition being raised by a call from NetBeans code - I wonder if this is a NetBeans error or if this case should be ignored by the CheckThreadViolationRepaintManager code.


    2007-09-21 14:51:28,562 [main] ERROR com.acinion.sms.util.ui.CheckThreadViolationRepaintManager - EDT violation detected: javax.swing.JPanel[,0,0,0x0,invalid,layout=java.awt.FlowLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=9,maximumSize=,minimumSize=,preferredSize=]
    at org.jdesktop.swinghelper.debug.CheckThreadViolationRepaintManager.checkThreadViolations(CheckThreadViolationRepaintManager.java:111)
    at org.jdesktop.swinghelper.debug.CheckThreadViolationRepaintManager.addDirtyRegion(CheckThreadViolationRepaintManager.java:69)
    at javax.swing.JComponent.repaint(JComponent.java:4714)
    at java.awt.Component.repaint(Component.java:2924)
    at javax.swing.JComponent.setFont(JComponent.java:2720)
    at javax.swing.LookAndFeel.installColorsAndFont(LookAndFeel.java:190)
    at javax.swing.plaf.basic.BasicPanelUI.installDefaults(BasicPanelUI.java:49)
    at javax.swing.plaf.basic.BasicPanelUI.installUI(BasicPanelUI.java:39)
    at javax.swing.JComponent.setUI(JComponent.java:668)
    at javax.swing.JPanel.setUI(JPanel.java:136)
    at javax.swing.JPanel.updateUI(JPanel.java:109)
    at javax.swing.JPanel.(JPanel.java:69)
    at javax.swing.JPanel.(JPanel.java:92)
    at javax.swing.JPanel.(JPanel.java:100)
    at org.netbeans.TopSecurityManager.makeSwingUseSpecialClipboard(TopSecurityManager.java:477)
    at org.netbeans.core.NonGui.run(NonGui.java:132)
    at org.netbeans.core.startup.Main.start(Main.java:401)
    at org.netbeans.core.startup.TopThreadGroup.run(TopThreadGroup.java:96)
    at java.lang.Thread.run(Thread.java:619)


    I worked around it by adding the following check:

    if ( "javax.swing.JComponent".equals( st.getClassName() ) &&
    "setUI".equals( st.getMethodName() ) )
    return;

    Posted by: dave_nedde on September 21, 2007 at 12:48 PM

  • Hello Dave
    It looks like NetBeans calls updateUI outside EDT which is suspicious
    setUI() has to be called on EDT as well, so
    could you file a bug on NetBeans providing your test case ?
    Thanks
    alexp

    Posted by: alexfromsun on September 24, 2007 at 12:55 AM

  • You say: "Initially there was a rule that it is safe to create and use Swing components until they are realized
    but this rule is not valid any more, and now it is recommended to interact with Swing from EDT only"

    This was surprising to me. After some googling, I am slowly realizing there has been a kind of "underadvertized" policy change regarding this. May I ask, why is this the case?

    I note that here, in the same Sun documentation that you link to above, ImageIcons are created, unrealized, out of the EDT, and later used in the done method inside the EDT.

    Taken on its face, I guess from your statement that approximately 99% of the world's Swing programs are unsafe?

    Refactoring to support this kind of restriction is non-trivial.

    So, what caused this restriction? And is it truly uniform, or does it apply only to i.e. creating Frames?

    Posted by: obsidian01 on January 25, 2008 at 08:54 AM

  • Hello Obsidian01
    The old poilicy was just incorrect and that was the main reason why it was changed
    if you create a component on main thread it fires its listeners,
    which are notified on EDT, so it is impossible to keep a component
    in a valid state if it is accessed from multilpe thread at the same time
    because Swing is not thread safe (like all of the rest modern GUI libraries)
    It workes somehow (probably most of the time) if you follow the old rulebut we don't guarantee that you won't see a strange exception sometimewhen you run your application on multi core machine or on another operating system
    work with Swing on EDT (including creating of JFrames ) and you will be on the safe side
    as for ImageIcons - they are just another icon implementation,
    when I say "interact with Swing" - I mean components and parts of the components (like models)
    so ImageIcon is an exception
    Thanks
    alexp

    Posted by: alexfromsun on January 27, 2008 at 03:15 PM

  • Very interesting.


    When you said "components and parts of the components (like models)," are you saying that this restriction normally applies not only to Swing Components, but to model objects as well, so combo box models and so forth? Even if they, too, are "unrealized" - not attached to a Component?


    It would help to understand more of the reason behind this. If I create a new JPanel, and it sits alone, un-added and un-painted, what events have been fired, and to what listeners?

    Posted by: obsidian01 on January 28, 2008 at 09:02 PM

  • Hello Obsidian01

    While it is certainly possilble to find some exceptions,
    like creating unrealized model on another thread,
    it doesn't change the main rule about Swing only on EDT

    it might be ok to create an empty, un-added and up-painted JPane(if such a component is useful for your application)


    I don't have a test case which always fail when you incorrectly work with Swing
    because if you work with not thread safe object from multilple threads you have unstable results, it may seem to work on one machine 10 times in a row but fail for the next start
    Thanks
    alexp

    Posted by: alexfromsun on January 29, 2008 at 05:56 AM

  • Hi Alex,

    You're saying "if you create a component on main thread it fires its listeners,
    which are notified on EDT, so it is impossible to keep a component
    in a valid state". Sure, this will cause problems with threading. But, what kind of events components which are not yet showing will get from EDT? Container events, hierarchy events?

    Posted by: ivan_p on February 14, 2008 at 09:18 AM

  • Hello Ivan
    Yes, container events, hierarchy events, model change events, property change events etc...

    alexp

    Posted by: alexfromsun on February 14, 2008 at 10:17 AM

  • Hi Alex,

    I've got EDT violation when testing with my app that uses animated GIFs:

    java.lang.Exception
    at com.emo.CheckThreadViolationRepaintManager.checkThreadViolations(CheckThreadViolationRepaintManager.java:42)
    at com.emo.CheckThreadViolationRepaintManager.addDirtyRegion(CheckThreadViolationRepaintManager.java:34)
    at javax.swing.JComponent.repaint(JComponent.java:4714)
    at java.awt.Component.imageUpdate(Component.java:3140)
    at javax.swing.AbstractButton.imageUpdate(AbstractButton.java:2201)
    at sun.awt.image.ImageWatched$WeakLink.newInfo(ImageWatched.java:114)
    at sun.awt.image.ImageWatched.newInfo(ImageWatched.java:151)
    at sun.awt.image.ImageRepresentation.setPixels(ImageRepresentation.java:466)
    at sun.awt.image.ImageDecoder.setPixels(ImageDecoder.java:108)
    at sun.awt.image.GifImageDecoder.sendPixels(GifImageDecoder.java:430)
    at sun.awt.image.GifImageDecoder.parseImage(Native Method)
    at sun.awt.image.GifImageDecoder.readImage(GifImageDecoder.java:572)
    at sun.awt.image.GifImageDecoder.produceImage(GifImageDecoder.java:195)
    at sun.awt.image.InputStreamImageSource.doFetch(InputStreamImageSource.java:246)
    at sun.awt.image.ImageFetcher.fetchloop(ImageFetcher.java:172)
    at sun.awt.image.ImageFetcher.run(ImageFetcher.java:136)

    Posted by: pk_thoo on February 19, 2008 at 11:25 PM

  • Hello Pk_thoo

    Did you test the latest CheckThreadViolationRepaintManager
    from SwingHelper project?
    Thanks
    alexp

    Posted by: alexfromsun on February 21, 2008 at 02:31 AM

  • Hello Alex,

    I've used CheckThreadViolationRepaintManager from the first code-block at the top.

    When you referred SwingHelper project, I visited there and came back here when I click on CheckThreadViolationRepaintManager link.

    So, the answer to your question is Yes.

    I am hoping if anyone else can confirm that they have encountered EDT violations (when tested with CheckThreadViolationRepaintManager ) in their Swing apps when using animated GIFs.

    Thanks Alex.

    Posted by: pk_thoo on February 25, 2008 at 06:20 PM

  • I, too, use animated gifs and also experienced lengthy EDT violation logs due to it . I added a getter and setter for a new variable named ignoreThisComponent and then modified the checkThread method as follows:


    private void checkThread(JComponent c) {
    if(c == getIgnoreThisComponent()) {
    return;
    }
    if(!SwingUtilities.isEventDispatchThread() && checkIsShowing(c)) {
    System.out.println("----------Wrong Thread START");
    System.out.println(getStracktraceAsString(new Exception("EDT Violation")));
    dumpComponentTree(c);
    System.out.println("----------Wrong Thread END");
    }
    }

    Posted by: forcers on March 04, 2008 at 12:14 PM

  • Hello guys

    The latest version of the CheckThreadViolationRepaintManager
    is placed on the SwingHelper under "Debugging and testing" title;just in case here the direct pointers - debug.jar
    and debug-src.zip
    ,you can also browse the CVS repository

    I fixed some problems with erroneous detections of EDT violations so please try the latest version of the CheckThreadViolationRepaintManager

    Thanks
    alexp

    Posted by: alexfromsun on March 05, 2008 at 03:42 AM

  • I tried the aspect, but it doesn't detect constructors for subclasses of JFrame. Is it on purpose ?

    Posted by: utilisateur_768 on April 21, 2008 at 02:12 AM

  • Here again with the aspect. Some code is detected as Swing while it is not:

    The "Object Map.get(Object)" is advised by EdtRuleChecker.before(JComponent): anySwingMethods(BindingTypePattern(javax.swing.JComponent, 0))..

    Posted by: utilisateur_768 on April 21, 2008 at 02:36 AM

  • Hello utilisateur

    Constructors for JFrame is a good catch!
    I should add them to the aspect

    Could you send me an example of the code
    which is erroneously detected as the Swing code?

    Thanks
    alexp

    Posted by: alexfromsun on April 21, 2008 at 04:55 AM

  • The 2 lines with "//here" comment are marked (in eclipse)


    public class Test {
    private static Map map = new HashMap();

    public void foo() throws IOException {
    if ("const".equals(map.get("nom"))) { // here
    String s = (String)map.get("nom-sauvegarde-projet");
    s += "";
    }

    JarFile fichierJar = new JarFile("foo.jar");

    Enumeration enu = fichierJar.entries();
    while (enu.hasMoreElements()) { // here
    JarEntry je = enu.nextElement();
    je.clone();
    }

    }
    }

    Posted by: utilisateur_768 on April 22, 2008 at 04:24 AM

  • Hello utilisateur
    I might be missing something,
    but I don't see any connection between your test case and Swing EDT issues

    Do you mean that eclipse IDE marks that code as suspicious
    or it my aspect did it?
    Thanks
    alexp

    Posted by: alexfromsun on April 22, 2008 at 04:42 AM

  • I my (big) java application, some lines get detected by eclipse AOP plugin with your aspect. I have put these lines in the small test case above.

    Eclipse (with the plugin) just put markers to the lines concerned with your aspect, and some of them are just wrong.


    Posted by: utilisateur_768 on April 22, 2008 at 07:00 AM

  • May be with the plugin output, it will be more simple:

    Here are the method calls which are detected by your aspect (with eclipse Aspect J - AJDT). I think they should not be detected as swing method calls.

    Please tell me if you know why these lines are wrongly detected as swing method calls.


    foo()
    method-call(java.lang.Object java.util.Map.get(java.lang.Object))
    advised by
    EdtRuleChecker.before(JComponent): anySwingMethods(BindingTypePattern(javax.swing.JComponent, 0))..
    method-call(java.lang.Object java.util.Map.get(java.lang.Object))
    advised by
    EdtRuleChecker.before(JComponent): anySwingMethods(BindingTypePattern(javax.swing.JComponent, 0))..
    method-call(boolean java.util.Enumeration.hasMoreElements())
    advised by
    EdtRuleChecker.before(JComponent): anySwingMethods(BindingTypePattern(javax.swing.JComponent, 0))..
    method-call(java.lang.Object java.util.Enumeration.nextElement())
    advised by
    EdtRuleChecker.before(JComponent): anySwingMethods(BindingTypePattern(javax.swing.JComponent, 0))..


    In last resort it could be a bug in aspectJ or in the aspect J eclipse plugin.

    Posted by: utilisateur_768 on April 23, 2008 at 06:13 AM



Only logged in users may post comments. Login Here.


Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds