docs: public com.groupon.odo.proxylib.models.Method getMethod(String className, String methodName) throws Exception {
          // TODO: fix this so it returns the right override ID
          com.groupon.odo.proxylib.models.Method m = null;
  
          // calls getClass first in case the loaded class needs to be invalidated
          Class<?> gottenClass = getClass(className);
          ClassInformation classInfo = classInformation.get(className);
  
          String fullName = className + "." + methodName;
          if (methodInformation.containsKey(fullName)) {
              m = methodInformation.get(fullName);
          } else {
              logger.info("Getting method info: {}", fullName);
  
              // Make a new classpool with the system classpath URLS
              // We create a new classpool each time since we want to reload plugin information in case it has changed.
              // Once a method is loaded this should not get called so the extra expense is not always taken as a hit
              ClassPool classPool = new ClassPool();
              ClassLoader sysClassLoader = Thread.currentThread().getContextClassLoader();
  
              //Get the URLs
              URL[] urls = ((URLClassLoader) sysClassLoader).getURLs();
              for (int i = 0; i < urls.length; i++) {
                  try {
                      // insert all classpaths into the javassist classpool
                      File f1 = new File(urls[i].getFile());
  
                      if (f1.exists()) {
                          // only add if file exists to avoid an uncatchable exception in Java 8
                          classPool.insertClassPath(urls[i].getFile());
                      }
                  } catch (NotFoundException e) {
                      e.printStackTrace();
                  }
              }
              classPool.insertClassPath(classInfo.pluginPath);
  
              // load method information
              Method[] methods = gottenClass.getDeclaredMethods();
              for (Method method : methods) {
                  if (method.getName().compareTo(methodName) != 0) {
                      continue;
                  }
  
                  try {
                      // get annotation information
                      Annotation[] annotations = method.getAnnotations();
                      for (Annotation annotation : annotations) {
                          com.groupon.odo.proxylib.models.Method newMethod = new com.groupon.odo.proxylib.models.Method();
                          newMethod.setClassName(className);
                          newMethod.setMethodName(methodName);
                          newMethod.setMethod(method);
                          newMethod.setMethodType(annotation.annotationType().toString());
  
                          String[] argNames = null;
                          String[] defaultArgs = null;
                          String description = null;
  
                          // Convert to the right type and get annotation information
                          if (annotation.annotationType().toString().endsWith(Constants.PLUGIN_RESPONSE_OVERRIDE_CLASS)) {
                              ResponseOverride roAnnotation = (ResponseOverride) annotation;
                              newMethod.setHttpCode(roAnnotation.httpCode());
                              description = roAnnotation.description();
                              argNames = roAnnotation.parameters();
                              defaultArgs = new String[0];
                              newMethod.setOverrideVersion(1);
                          } else if (annotation.annotationType().toString().endsWith(Constants.PLUGIN_RESPONSE_OVERRIDE_V2_CLASS)) {
                              com.groupon.odo.plugin.v2.ResponseOverride roAnnotation = (com.groupon.odo.plugin.v2.ResponseOverride) annotation;
                              description = roAnnotation.description();
                              argNames = roAnnotation.parameters();
                              defaultArgs = roAnnotation.argDefaults();
                              newMethod.setBlockRequest(roAnnotation.blockRequest());
                              newMethod.setOverrideVersion(2);
                          } else {
                              continue;
                          }
  
                          // identify arguments
                          // first arg is always a reserved that we skip
                          ArrayList<String> params = new ArrayList<String>();
                          if (method.getParameterTypes().length > 1) {
                              for (int x = 1; x < method.getParameterTypes().length; x++) {
                                  params.add(method.getParameterTypes()[x].getName());
                              }
                          }
                          newMethod.setMethodArguments(params.toArray(new Object[0]));
                          newMethod.setMethodArgumentNames(argNames);
                          newMethod.setMethodDefaultArguments(defaultArgs);
                          newMethod.setDescription(description);
                          newMethod.setIdString(className + "." + methodName);
  
                          methodInformation.put(fullName, newMethod);
                          m = newMethod;
                      }
  
                      break;
                  } catch (Exception e) {
                      // in this case we just return null since the method would be unuseable
                      return null;
                  }
              }
          }
  
          return m;
      }