Search code examples
javaswingexceptionrepaintmanager

How to generate exceptions from RepaintManager


In connection with my question (may be), I found another exception type that I not able to catch and print-out from SwingWorker thread.

How can I to generate RepaintManager exceptions?

I read this CheckThreadViolationRepaintManager and this approach by Alexander Potochkin, but nothing seems to solve my issues.


Solution

  • If it helps, the example below throws prints multiple variations of the following Exception, mostly for each phase of the frame's UI delegate initialization. I used CheckThreadViolationRepaintManager, but the AspectJ variation looks interesting, too.

    java.lang.Exception
        at EDTViolation$CheckThreadViolationRepaintManager.checkThreadViolations(EDTViolation.java:43)
        at EDTViolation$CheckThreadViolationRepaintManager.addDirtyRegion(EDTViolation.java:37)
        at javax.swing.JComponent.repaint(JComponent.java:4734)
        at java.awt.Component.repaint(Component.java:3168)
        at javax.swing.JComponent.setFont(JComponent.java:2727)
        at javax.swing.LookAndFeel.installColorsAndFont(LookAndFeel.java:191)
        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:662)
        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 javax.swing.JRootPane.createGlassPane(JRootPane.java:528)
        at javax.swing.JRootPane.(JRootPane.java:348)
        at javax.swing.JFrame.createRootPane(JFrame.java:255)
        at javax.swing.JFrame.frameInit(JFrame.java:236)
        at javax.swing.JFrame.(JFrame.java:159)
        at EDTViolation.main(EDTViolation.java:12)
    ...
    
    import java.lang.ref.WeakReference;
    import javax.swing.JComponent;
    import javax.swing.JFrame;
    import javax.swing.RepaintManager;
    import javax.swing.SwingUtilities;
    
    /** @see https://stackoverflow.com/questions/7787998 */
    public class EDTViolation {
    
        public static void main(String args[]) {
            RepaintManager.setCurrentManager(new CheckThreadViolationRepaintManager());
            JFrame f = new JFrame();
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.pack();
            f.setVisible(true);
        }
        
        private static class CheckThreadViolationRepaintManager extends RepaintManager {
        //http://weblogs.java.net/blog/alexfromsun/archive/2006/02/debugging_swing.html
    
            private boolean completeCheck = true;
            private WeakReference<JComponent> lastComponent;
    
            public CheckThreadViolationRepaintManager(boolean completeCheck) {
                this.completeCheck = completeCheck;
            }
    
            public CheckThreadViolationRepaintManager() {
                this(true);
            }
    
            public boolean isCompleteCheck() {
                return completeCheck;
            }
    
            public void setCompleteCheck(boolean completeCheck) {
                this.completeCheck = completeCheck;
            }
    
            @Override
            public synchronized void addInvalidComponent(JComponent component) {
                checkThreadViolations(component);
                super.addInvalidComponent(component);
            }
    
            @Override
            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())) {
                    boolean repaint = false;
                    boolean fromSwing = false;
                    boolean imageUpdate = false;
                    StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
                    for (StackTraceElement st : stackTrace) {
                        if (repaint && st.getClassName().startsWith("javax.swing.")
                            && // for details see 
                            // https://swinghelper.dev.java.net/issues/show_bug.cgi?id=1
                            !st.getClassName().startsWith("javax.swing.SwingWorker")) {
                            fromSwing = true;
                        }
                        if (repaint && "imageUpdate".equals(st.getMethodName())) {
                            imageUpdate = true;
                        }
                        if ("repaint".equals(st.getMethodName())) {
                            repaint = true;
                            fromSwing = false;
                        }
                        if ("read".equals(st.getMethodName()) && "javax.swing.JEditorPane".equals(st.getClassName())) {
                            // Swing reads html from a background thread
                            return;
                        }
                    }
                    if (imageUpdate) {
                    //assuming it is java.awt.image.ImageObserver.imageUpdate(...) 
                        //image was asynchronously updated, that's ok 
                        return;
                    }
                    if (repaint && !fromSwing) {
                        //no problems here, since repaint() is thread safe
                        return;
                    }
                    //ignore the last processed component
                    if (lastComponent != null && c == lastComponent.get()) {
                        return;
                    }
                    lastComponent = new WeakReference<JComponent>(c);
                    violationFound(c, stackTrace);
                }
            }
    
            protected void violationFound(JComponent c, StackTraceElement[] stackTrace) {
                System.out.println();
                System.out.println("EDT violation detected");
                System.out.println(c);
                for (StackTraceElement st : stackTrace) {
                    System.out.println("\tat " + st);
                }
            }
        }
    }