diff --git a/spring-core/src/main/java/org/springframework/core/NestedCheckedException.java b/spring-core/src/main/java/org/springframework/core/NestedCheckedException.java index 23c7ceb16e..0cb2920dce 100644 --- a/spring-core/src/main/java/org/springframework/core/NestedCheckedException.java +++ b/spring-core/src/main/java/org/springframework/core/NestedCheckedException.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -80,13 +80,7 @@ public abstract class NestedCheckedException extends Exception { * @return the innermost exception, or {@code null} if none */ public Throwable getRootCause() { - Throwable rootCause = null; - Throwable cause = getCause(); - while (cause != null && cause != rootCause) { - rootCause = cause; - cause = cause.getCause(); - } - return rootCause; + return NestedExceptionUtils.getRootCause(this); } /** diff --git a/spring-core/src/main/java/org/springframework/core/NestedExceptionUtils.java b/spring-core/src/main/java/org/springframework/core/NestedExceptionUtils.java index 8b66390f46..e7c11aed75 100644 --- a/spring-core/src/main/java/org/springframework/core/NestedExceptionUtils.java +++ b/spring-core/src/main/java/org/springframework/core/NestedExceptionUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,17 +39,48 @@ public abstract class NestedExceptionUtils { * @return the full exception message */ public static String buildMessage(String message, Throwable cause) { - if (cause != null) { - StringBuilder sb = new StringBuilder(); - if (message != null) { - sb.append(message).append("; "); - } - sb.append("nested exception is ").append(cause); - return sb.toString(); - } - else { + if (cause == null) { return message; } + StringBuilder sb = new StringBuilder(64); + if (message != null) { + sb.append(message).append("; "); + } + sb.append("nested exception is ").append(cause); + return sb.toString(); + } + + /** + * Retrieve the innermost cause of the given exception, if any. + * @param original the original exception to introspect + * @return the innermost exception, or {@code null} if none + * @since 4.3.9 + */ + public static Throwable getRootCause(Throwable original) { + if (original == null) { + return null; + } + Throwable rootCause = null; + Throwable cause = original.getCause(); + while (cause != null && cause != rootCause) { + rootCause = cause; + cause = cause.getCause(); + } + return rootCause; + } + + /** + * Retrieve the most specific cause of the given exception, that is, + * either the innermost cause (root cause) or the exception itself. + *
Differs from {@link #getRootCause} in that it falls back
+ * to the original exception if there is no root cause.
+ * @param original the original exception to introspect
+ * @return the most specific cause (never {@code null})
+ * @since 4.3.9
+ */
+ public static Throwable getMostSpecificCause(Throwable original) {
+ Throwable rootCause = getRootCause(original);
+ return (rootCause != null ? rootCause : original);
}
}
diff --git a/spring-core/src/main/java/org/springframework/core/NestedRuntimeException.java b/spring-core/src/main/java/org/springframework/core/NestedRuntimeException.java
index 8d20d81f88..6e8843f0f8 100644
--- a/spring-core/src/main/java/org/springframework/core/NestedRuntimeException.java
+++ b/spring-core/src/main/java/org/springframework/core/NestedRuntimeException.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -81,13 +81,7 @@ public abstract class NestedRuntimeException extends RuntimeException {
* @since 2.0
*/
public Throwable getRootCause() {
- Throwable rootCause = null;
- Throwable cause = getCause();
- while (cause != null && cause != rootCause) {
- rootCause = cause;
- cause = cause.getCause();
- }
- return rootCause;
+ return NestedExceptionUtils.getRootCause(this);
}
/**
diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/AbstractSockJsSession.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/AbstractSockJsSession.java
index c8a45096e3..925f36b67f 100644
--- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/AbstractSockJsSession.java
+++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/AbstractSockJsSession.java
@@ -19,7 +19,6 @@ package org.springframework.web.socket.sockjs.transport.session;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
@@ -31,7 +30,7 @@ import java.util.concurrent.ScheduledFuture;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.springframework.core.NestedCheckedException;
+import org.springframework.core.NestedExceptionUtils;
import org.springframework.util.Assert;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
@@ -70,25 +69,22 @@ public abstract class AbstractSockJsSession implements SockJsSession {
public static final String DISCONNECTED_CLIENT_LOG_CATEGORY =
"org.springframework.web.socket.sockjs.DisconnectedClient";
+ /**
+ * Tomcat: ClientAbortException or EOFException
+ * Jetty: EofException
+ * WildFly, GlassFish: java.io.IOException "Broken pipe" (already covered)
+ * @see #indicatesDisconnectedClient(Throwable)
+ */
+ private static final Set