001/*
002 * Copyright 2002-2017 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.core;
018
019/**
020 * Helper class for implementing exception classes which are capable of
021 * holding nested exceptions. Necessary because we can't share a base
022 * class among different exception types.
023 *
024 * <p>Mainly for use within the framework.
025 *
026 * @author Juergen Hoeller
027 * @since 2.0
028 * @see NestedRuntimeException
029 * @see NestedCheckedException
030 * @see NestedIOException
031 * @see org.springframework.web.util.NestedServletException
032 */
033public abstract class NestedExceptionUtils {
034
035        /**
036         * Build a message for the given base message and root cause.
037         * @param message the base message
038         * @param cause the root cause
039         * @return the full exception message
040         */
041        public static String buildMessage(String message, Throwable cause) {
042                if (cause == null) {
043                        return message;
044                }
045                StringBuilder sb = new StringBuilder(64);
046                if (message != null) {
047                        sb.append(message).append("; ");
048                }
049                sb.append("nested exception is ").append(cause);
050                return sb.toString();
051        }
052
053        /**
054         * Retrieve the innermost cause of the given exception, if any.
055         * @param original the original exception to introspect
056         * @return the innermost exception, or {@code null} if none
057         * @since 4.3.9
058         */
059        public static Throwable getRootCause(Throwable original) {
060                if (original == null) {
061                        return null;
062                }
063                Throwable rootCause = null;
064                Throwable cause = original.getCause();
065                while (cause != null && cause != rootCause) {
066                        rootCause = cause;
067                        cause = cause.getCause();
068                }
069                return rootCause;
070        }
071
072        /**
073         * Retrieve the most specific cause of the given exception, that is,
074         * either the innermost cause (root cause) or the exception itself.
075         * <p>Differs from {@link #getRootCause} in that it falls back
076         * to the original exception if there is no root cause.
077         * @param original the original exception to introspect
078         * @return the most specific cause (never {@code null})
079         * @since 4.3.9
080         */
081        public static Throwable getMostSpecificCause(Throwable original) {
082                Throwable rootCause = getRootCause(original);
083                return (rootCause != null ? rootCause : original);
084        }
085
086}