code: public static Throwable getChainedException(Throwable th) {
          java.lang.reflect.Method[] methods = th.getClass().getMethods();
  
          // Need to keep looking if we find a valid method but it returns null. For some
          // throwables, like ResourceException, getLinkedException will be null but
          // getCause will be non-null, or vice versa. 
  
          Throwable chainedX = null; 
  
          for (int i = 0; i < methods.length && chainedX == null; i++)
  
              if (Throwable.class.isAssignableFrom(methods[i].getReturnType()) &&
                  !methods[i].getName().equals("getSQLException") && 
                  methods[i].getName().startsWith("get") && 
                  methods[i].getParameterTypes().length == 0 && 
                  (methods[i].getName().endsWith("Cause") || 
                   methods[i].getName().endsWith("Exception") || 
                   methods[i].getName().endsWith("Error") || 
                  methods[i].getName().endsWith("Warning"))) 
  
                  try {
                      chainedX = (Throwable) methods[i].invoke(th, (Object[]) null); 
                  } catch (Throwable ex) {
                      // No FFDC code needed; ignore.
                  }
  
          return chainedX; 
      }
docs: Retrieves the exception chained to the specified Throwable.
  For the purposes of this method, chained exception accessors are defined as
  any zero-parameter method returning a Throwable and having a name of:
  get*Cause, get*Exception, get*Error, get*Warning.
  
  If multiple accessors exist, each is tried until one returns a non-null result.
  
  @param th the Exception or Error to retrieve the chained exception of.
  
  @return the chained exception, or null if there is no chained exception.