This is an automated email from the ASF dual-hosted git repository.
garydgregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-lang.git
The following commit(s) were added to refs/heads/master by this push:
new 4060e60f4 Stop ExceptionUtils.removeCommonFrames at the first
differing frame (#1831)
4060e60f4 is described below
commit 4060e60f45338ff337a145bd55bf1541353d8e3d
Author: alhuda <[email protected]>
AuthorDate: Sun Oct 25 18:22:27 2026 +0530
Stop ExceptionUtils.removeCommonFrames at the first differing frame (#1831)
Common frames are the trailing run shared by the cause and wrapper
traces, as folded by Throwable.printStackTrace into "... n more".
removeCommonFrames kept comparing past the first mismatch and removed
any frame that matched again at the same offset, so the root-cause
trace printed by getRootCauseStackTrace lost real frames, including
the frame where the cause was created when a shared factory method
builds both exceptions.
---
.../commons/lang3/exception/ExceptionUtils.java | 7 ++++---
.../lang3/exception/ExceptionUtilsTest.java | 23 ++++++++++++++++++++++
2 files changed, 27 insertions(+), 3 deletions(-)
diff --git
a/src/main/java/org/apache/commons/lang3/exception/ExceptionUtils.java
b/src/main/java/org/apache/commons/lang3/exception/ExceptionUtils.java
index ade1eaec4..2c5bed6a2 100644
--- a/src/main/java/org/apache/commons/lang3/exception/ExceptionUtils.java
+++ b/src/main/java/org/apache/commons/lang3/exception/ExceptionUtils.java
@@ -923,12 +923,13 @@ public static void removeCommonFrames(final List<String>
causeFrames, final List
int wrapperFrameIndex = wrapperFrames.size() - 1;
while (causeFrameIndex >= 0 && wrapperFrameIndex >= 0) {
// Remove the frame from the cause trace if it is the same
- // as in the wrapper trace
+ // as in the wrapper trace; common frames end at the first
difference
final String causeFrame = causeFrames.get(causeFrameIndex);
final String wrapperFrame = wrapperFrames.get(wrapperFrameIndex);
- if (causeFrame.equals(wrapperFrame)) {
- causeFrames.remove(causeFrameIndex);
+ if (!causeFrame.equals(wrapperFrame)) {
+ break;
}
+ causeFrames.remove(causeFrameIndex);
causeFrameIndex--;
wrapperFrameIndex--;
}
diff --git
a/src/test/java/org/apache/commons/lang3/exception/ExceptionUtilsTest.java
b/src/test/java/org/apache/commons/lang3/exception/ExceptionUtilsTest.java
index 533acce5b..a52f34d0d 100644
--- a/src/test/java/org/apache/commons/lang3/exception/ExceptionUtilsTest.java
+++ b/src/test/java/org/apache/commons/lang3/exception/ExceptionUtilsTest.java
@@ -913,6 +913,29 @@ void testRemoveCommonFrames_ListList() {
assertNullPointerException(() ->
ExceptionUtils.removeCommonFrames(null, null));
}
+ @Test
+ void testRemoveCommonFramesStopsAtFirstDifference() {
+ final List<String> causeFrames = new ArrayList<>(Arrays.asList("\tat
a.Factory.create(Factory.java:1)", "\tat a.B.one(B.java:2)",
+ "\tat a.B.main(B.java:9)"));
+ final List<String> wrapperFrames = Arrays.asList("\tat
a.Factory.create(Factory.java:1)", "\tat a.B.two(B.java:5)",
+ "\tat a.B.main(B.java:9)");
+ ExceptionUtils.removeCommonFrames(causeFrames, wrapperFrames);
+ assertEquals(Arrays.asList("\tat a.Factory.create(Factory.java:1)",
"\tat a.B.one(B.java:2)"), causeFrames);
+ }
+
+ @Test
+ void testRootCauseStackTraceKeepsSharedFactoryFrame() {
+ final RuntimeException cause = newRuntimeException("cause", null);
+ final RuntimeException wrapper = newRuntimeException("wrapper", cause);
+ final List<String> frames =
ExceptionUtils.getRootCauseStackTraceList(wrapper);
+ assertEquals(cause.toString(), frames.get(0));
+ assertTrue(frames.get(1).contains("newRuntimeException"),
frames.get(1));
+ }
+
+ private static RuntimeException newRuntimeException(final String message,
final Throwable cause) {
+ return new RuntimeException(message, cause);
+ }
+
@Test
void testRethrow() {
final Exception expected = new InterruptedException();