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