public Object callMethod(Object o, String methodName, Object... args)
      throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {

    Method method = null;
    
    if (args == null || args.length == 0) {
      method = o.getClass().getDeclaredMethod(methodName);
    } else {
      Class<?>[] types = new Class[args.length];
      for (int i = 0; i < args.length; i++) {
        types[i] = args[i].getClass();
      }
      try {
        method = o.getClass().getDeclaredMethod(methodName, types);
      } catch (NoSuchMethodException e) {
        // Try more complex comparison for matching args to supertypes in the params
        method = findSupertypeMethod(o, methodName, types);
      }
    }
    
    if (method == null) {
      throw new NoSuchMethodException("Found no method named" + methodName + " with matching params");
    }
    
    method.setAccessible(true);
    
    return method.invoke(o, args);
  }