public static <R> R callInstanceMethod(
      final Object instance, final String methodName, ClassParameter<?>... classParameters) {
    perfStatsCollector.incrementCount(
        String.format(
            "ReflectionHelpers.callInstanceMethod-%s_%s",
            instance.getClass().getName(), methodName));
    try {
      final Class<?>[] classes = ClassParameter.getClasses(classParameters);
      final Object[] values = ClassParameter.getValues(classParameters);

      return traverseClassHierarchy(
          instance.getClass(),
          NoSuchMethodException.class,
          traversalClass -> {
            Method declaredMethod = traversalClass.getDeclaredMethod(methodName, classes);
            declaredMethod.setAccessible(true);
            return (R) declaredMethod.invoke(instance, values);
          });
    } catch (InvocationTargetException e) {
      if (e.getTargetException() instanceof RuntimeException) {
        throw (RuntimeException) e.getTargetException();
      }
      if (e.getTargetException() instanceof Error) {
        throw (Error) e.getTargetException();
      }
      throw new RuntimeException(e.getTargetException());
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }
@Test
  public void callInstanceMethodReflectively_rethrowsError() {
    ExampleDescendant example = new ExampleDescendant();
    try {
      ReflectionHelpers.callInstanceMethod(example, "throwError");
      fail("Expected exception not thrown");
    } catch (RuntimeException e) {
      throw new RuntimeException("Incorrect exception thrown", e);
    } catch (TestError e) {
    }
  }