public static Void unwrapAndThrowException(ServiceException se)
      throws IOException, YarnException {
    Throwable cause = se.getCause();
    if (cause == null) {
      // SE generated by the RPC layer itself.
      throw new IOException(se);
    } else {
      if (cause instanceof RemoteException) {
        RemoteException re = (RemoteException) cause;
        Class<?> realClass = null;
        try {
          realClass = Class.forName(re.getClassName());
        } catch (ClassNotFoundException cnf) {
          // Assume this to be a new exception type added to YARN. This isn't
          // absolutely correct since the RPC layer could add an exception as
          // well.
          throw instantiateYarnException(YarnException.class, re);
        }

        if (YarnException.class.isAssignableFrom(realClass)) {
          throw instantiateYarnException(
              realClass.asSubclass(YarnException.class), re);
        } else if (IOException.class.isAssignableFrom(realClass)) {
          throw instantiateIOException(realClass.asSubclass(IOException.class),
              re);
        } else if (RuntimeException.class.isAssignableFrom(realClass)) {
          throw instantiateRuntimeException(
              realClass.asSubclass(RuntimeException.class), re);
        } else {
          throw re;
        }
        // RemoteException contains useful information as against the
        // java.lang.reflect exceptions.

      } else if (cause instanceof IOException) {
        // RPC Client exception.
        throw (IOException) cause;
      } else if (cause instanceof RuntimeException) {
        // RPC RuntimeException
        throw (RuntimeException) cause;
      } else {
        // Should not be generated.
        throw new IOException(se);
      }
    }
  }
@Test
  void testRPCServiceExceptionUnwrapping() {
    String message = "ServiceExceptionMessage";
    ServiceException se = new ServiceException(message);

    Throwable t = null;
    try {
      RPCUtil.unwrapAndThrowException(se);
    } catch (Throwable thrown) {
      t = thrown;
    }

    assertTrue(IOException.class.isInstance(t));
    assertTrue(t.getMessage().contains(message));
  }