code: public static <T extends Annotation> List<Method> findMethodsWithAnnotation(Class<?> type, Class<T> annotationType) {
      ClassAnnotationCacheKey cacheKey = new ClassAnnotationCacheKey(type, annotationType);
      List<Method> cachedResults = METHODS_WITH_ANNOTATION_CACHE.get(cacheKey);
  
      if (cachedResults != null) {
        return cachedResults;
      }
  
      List<Method> methodsWithAnnotation = new ArrayList<>();
  
      // Walk all superclasses looking for annotated methods until we hit Object
      while (!Object.class.equals(type)) {
        for (Method method : type.getDeclaredMethods()) {
          T annotation = method.getAnnotation(annotationType);
  
          if (annotation != null) {
            methodsWithAnnotation.add(method);
          }
        }
  
        type = type.getSuperclass();
      }
  
      methodsWithAnnotation = unmodifiableList(methodsWithAnnotation);
      METHODS_WITH_ANNOTATION_CACHE.put(cacheKey, methodsWithAnnotation);
      return methodsWithAnnotation;
    }
docs: Finds methods on the given {@code type} and all of its superclasses annotated with annotations of type
  {@code annotationType}.
  <p>
  These results are cached to mitigate performance overhead.
  
  @param <T>
  The annotation type.
  @param type
  The target type token.
  @param annotationType
  The annotation type token.
  @return A list of methods with the given annotation.
  @since 1.6.11