diff --git a/core/src/main/java/jenkins/util/io/CompositeIOException.java b/core/src/main/java/jenkins/util/io/CompositeIOException.java index fb325870f6..d1ff484c91 100644 --- a/core/src/main/java/jenkins/util/io/CompositeIOException.java +++ b/core/src/main/java/jenkins/util/io/CompositeIOException.java @@ -43,7 +43,7 @@ public class CompositeIOException extends IOException { * {@code CompositeIOException}. *

* The number of exceptions is limited to avoid pathological cases where - * where a huge number of exceptions could lead to excessive memory usage. + * a huge number of exceptions could lead to excessive memory usage. * For example, if the number of exceptions was unlimited, a call to * {@code Util.deleteRecursive} could fail with a * {@code CompositeIOException} that contains an exception for every @@ -58,15 +58,13 @@ public class CompositeIOException extends IOException { * exceptions are added as suppressed exceptions to the new exception. *

* If the given list of exceptions is longer than {@link #EXCEPTION_LIMIT}, - * the list will be truncated to that length, and an exception whose message - * contains the number of exceptions that were removed will be added as a - * suppressed exception to the new exception. + * the list will be truncated to that length, and a message indicating the + * number of discarded exceptions will be appended to the original message. */ public CompositeIOException(String message, @NonNull List exceptions) { - super(message); + super(message + getDiscardedExceptionsMessage(exceptions)); if (exceptions.size() > EXCEPTION_LIMIT) { this.exceptions = new ArrayList<>(exceptions.subList(0, EXCEPTION_LIMIT)); - this.exceptions.add(new ExceptionLimitReached(exceptions.size() - EXCEPTION_LIMIT)); } else { this.exceptions = exceptions; } @@ -88,21 +86,11 @@ public class CompositeIOException extends IOException { return new UncheckedIOException(this); } - /** - * An exception with no stack trace used to inform users that not all - * exceptions are being reported. - */ - private static class ExceptionLimitReached extends IOException { - private static final long serialVersionUID = 1L; - - public ExceptionLimitReached(int truncated) { - super(truncated + " additional exceptions were thrown"); - } - - @Override - public Throwable fillInStackTrace() { - // Do not create a strack trace for this exception. - return this; + private static String getDiscardedExceptionsMessage(List exceptions) { + if (exceptions.size() > EXCEPTION_LIMIT) { + return " (Discarded " + (exceptions.size() - EXCEPTION_LIMIT) + " additional exceptions)"; + } else { + return ""; } } } diff --git a/core/src/test/java/jenkins/util/io/PathRemoverTest.java b/core/src/test/java/jenkins/util/io/PathRemoverTest.java index 6a309cca68..f7754f75d2 100644 --- a/core/src/test/java/jenkins/util/io/PathRemoverTest.java +++ b/core/src/test/java/jenkins/util/io/PathRemoverTest.java @@ -55,6 +55,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.arrayWithSize; import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.endsWith; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasItem; import static org.junit.Assert.assertFalse; @@ -444,9 +445,8 @@ public class PathRemoverTest { PathRemover.newSimpleRemover().forceRemoveRecursive(dir.toPath()); fail("Deletion should have failed"); } catch (CompositeIOException e) { - assertThat(e.getSuppressed(), arrayWithSize(maxExceptions + 1)); - assertThat(e.getSuppressed()[maxExceptions].getMessage(), - containsString((lockedFiles + 1 - maxExceptions) + " additional exceptions")); + assertThat(e.getSuppressed(), arrayWithSize(maxExceptions)); + assertThat(e.getMessage(), endsWith("(Discarded" + (lockedFiles + 1 - maxExceptions) + " additional exceptions)")); } assertTrue(dir.exists()); assertThat(dir.listFiles().length, equalTo(lockedFiles));