Changeset 18549 in josm for trunk/src/org


Ignore:
Timestamp:
2022-09-06T18:40:21+02:00 (20 months ago)
Author:
taylor.smock
Message:

See #22183: NoClassDefFoundError: Could not initialize class org.openstreetmap.josm.actions.SessionSaveAction

The root cause is a suppressed NPE whose stack trace is not given
in the bug report.

This adds a method to BugReport to add suppressed exceptions to a report.
In the future, if we keep the code long-term, methods in Logging which take
exceptions may assume the exception is suppressed, and add it to the
suppressed exceptions.

Location:
trunk/src/org/openstreetmap/josm
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/gui/progress/swing/ProgressMonitorExecutor.java

    r18150 r18549  
    1111import org.openstreetmap.josm.tools.Logging;
    1212import org.openstreetmap.josm.tools.Utils;
     13import org.openstreetmap.josm.tools.bugreport.BugReport;
    1314
    1415/**
     
    5960        if (t != null) {
    6061            Logging.error("Thread {0} raised {1}", Thread.currentThread().getName(), t);
     62            BugReport.addSuppressedException(t);
    6163        }
    6264    }
  • trunk/src/org/openstreetmap/josm/gui/util/GuiHelper.java

    r18365 r18549  
    212212    static void handleEDTException(Throwable t) {
    213213        Logging.logWithStackTrace(Logging.LEVEL_ERROR, t, "Exception raised in EDT");
     214        BugReport.addSuppressedException(t);
    214215    }
    215216
  • trunk/src/org/openstreetmap/josm/tools/bugreport/BugReport.java

    r15735 r18549  
    55import java.io.Serializable;
    66import java.io.StringWriter;
     7import java.time.Instant;
     8import java.util.ArrayDeque;
     9import java.util.Deque;
    710import java.util.concurrent.CopyOnWriteArrayList;
    811import java.util.function.Predicate;
     12
     13import org.openstreetmap.josm.tools.Pair;
    914
    1015/**
     
    4045public final class BugReport implements Serializable {
    4146    private static final long serialVersionUID = 1L;
     47    /** The maximum suppressed exceptions to keep to report */
     48    private static final byte MAXIMUM_SUPPRESSED_EXCEPTIONS = 4;
     49    /** The list of suppressed exceptions, Pair<time reported, exception> */
     50    private static final Deque<Pair<Instant, Throwable>> SUPPRESSED_EXCEPTIONS = new ArrayDeque<>(MAXIMUM_SUPPRESSED_EXCEPTIONS);
    4251
    4352    private boolean includeStatusReport = true;
     
    5463        this.exception = e;
    5564        includeAllStackTraces = e.mayHaveConcurrentSource();
     65    }
     66
     67    /**
     68     * Add a suppressed exception. Mostly useful for when a chain of exceptions causes an actual bug report.
     69     * This should only be used when an exception is raised in {@link org.openstreetmap.josm.gui.util.GuiHelper}
     70     * or {@link org.openstreetmap.josm.gui.progress.swing.ProgressMonitorExecutor} at this time.
     71     * {@link org.openstreetmap.josm.tools.Logging} may call this in the future, when logging a throwable.
     72     * @param t The throwable raised. If {@code null}, we add a new {@code NullPointerException} instead.
     73     * @since 18549
     74     */
     75    public static void addSuppressedException(Throwable t) {
     76        SUPPRESSED_EXCEPTIONS.add(new Pair<>(Instant.now(), t != null ? t : new NullPointerException()));
     77        // Ensure we don't call pop in more than MAXIMUM_SUPPRESSED_EXCEPTIONS threads. This guard is
     78        // here just in case someone doesn't read the javadocs.
     79        synchronized (SUPPRESSED_EXCEPTIONS) {
     80            // Ensure we aren't keeping exceptions forever
     81            while (SUPPRESSED_EXCEPTIONS.size() > MAXIMUM_SUPPRESSED_EXCEPTIONS) {
     82                SUPPRESSED_EXCEPTIONS.pop();
     83            }
     84        }
    5685    }
    5786
     
    136165            exception.printReportThreadsTo(out);
    137166        }
     167        synchronized (SUPPRESSED_EXCEPTIONS) {
     168            if (!SUPPRESSED_EXCEPTIONS.isEmpty()) {
     169                out.println("=== ADDITIONAL EXCEPTIONS ===");
     170                // Avoid multiple bug reports from reading from the deque at the same time.
     171                while (SUPPRESSED_EXCEPTIONS.peek() != null) {
     172                    Pair<Instant, Throwable> currentException = SUPPRESSED_EXCEPTIONS.pop();
     173                    out.println("==== Exception at " + currentException.a.toEpochMilli() + " ====");
     174                    currentException.b.printStackTrace(out);
     175                }
     176            }
     177        }
    138178        return stringWriter.toString().replaceAll("\r", "");
    139179    }
Note: See TracChangeset for help on using the changeset viewer.