001/* 002 * Copyright 2002-2018 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 019import org.springframework.lang.Nullable; 020 021/** 022 * Handy class for wrapping checked {@code Exceptions} with a root cause. 023 * 024 * <p>This class is {@code abstract} to force the programmer to extend 025 * the class. {@code getMessage} will include nested exception 026 * information; {@code printStackTrace} and other like methods will 027 * delegate to the wrapped exception, if any. 028 * 029 * <p>The similarity between this class and the {@link NestedRuntimeException} 030 * class is unavoidable, as Java forces these two classes to have different 031 * superclasses (ah, the inflexibility of concrete inheritance!). 032 * 033 * @author Rod Johnson 034 * @author Juergen Hoeller 035 * @see #getMessage 036 * @see #printStackTrace 037 * @see NestedRuntimeException 038 */ 039public abstract class NestedCheckedException extends Exception { 040 041 /** Use serialVersionUID from Spring 1.2 for interoperability. */ 042 private static final long serialVersionUID = 7100714597678207546L; 043 044 static { 045 // Eagerly load the NestedExceptionUtils class to avoid classloader deadlock 046 // issues on OSGi when calling getMessage(). Reported by Don Brown; SPR-5607. 047 NestedExceptionUtils.class.getName(); 048 } 049 050 051 /** 052 * Construct a {@code NestedCheckedException} with the specified detail message. 053 * @param msg the detail message 054 */ 055 public NestedCheckedException(String msg) { 056 super(msg); 057 } 058 059 /** 060 * Construct a {@code NestedCheckedException} with the specified detail message 061 * and nested exception. 062 * @param msg the detail message 063 * @param cause the nested exception 064 */ 065 public NestedCheckedException(@Nullable String msg, @Nullable Throwable cause) { 066 super(msg, cause); 067 } 068 069 070 /** 071 * Return the detail message, including the message from the nested exception 072 * if there is one. 073 */ 074 @Override 075 @Nullable 076 public String getMessage() { 077 return NestedExceptionUtils.buildMessage(super.getMessage(), getCause()); 078 } 079 080 081 /** 082 * Retrieve the innermost cause of this exception, if any. 083 * @return the innermost exception, or {@code null} if none 084 */ 085 @Nullable 086 public Throwable getRootCause() { 087 return NestedExceptionUtils.getRootCause(this); 088 } 089 090 /** 091 * Retrieve the most specific cause of this exception, that is, 092 * either the innermost cause (root cause) or this exception itself. 093 * <p>Differs from {@link #getRootCause()} in that it falls back 094 * to the present exception if there is no root cause. 095 * @return the most specific cause (never {@code null}) 096 * @since 2.0.3 097 */ 098 public Throwable getMostSpecificCause() { 099 Throwable rootCause = getRootCause(); 100 return (rootCause != null ? rootCause : this); 101 } 102 103 /** 104 * Check whether this exception contains an exception of the given type: 105 * either it is of the given class itself or it contains a nested cause 106 * of the given type. 107 * @param exType the exception type to look for 108 * @return whether there is a nested exception of the specified type 109 */ 110 public boolean contains(@Nullable Class<?> exType) { 111 if (exType == null) { 112 return false; 113 } 114 if (exType.isInstance(this)) { 115 return true; 116 } 117 Throwable cause = getCause(); 118 if (cause == this) { 119 return false; 120 } 121 if (cause instanceof NestedCheckedException) { 122 return ((NestedCheckedException) cause).contains(exType); 123 } 124 else { 125 while (cause != null) { 126 if (exType.isInstance(cause)) { 127 return true; 128 } 129 if (cause.getCause() == cause) { 130 break; 131 } 132 cause = cause.getCause(); 133 } 134 return false; 135 } 136 } 137 138}