fork download
  1. import java.lang.annotation.*;
  2. import java.lang.reflect.*;
  3. import java.util.*;
  4.  
  5. @Retention(RetentionPolicy.RUNTIME)
  6. @interface Handler {}
  7. interface A<T> {
  8. @Handler
  9. void a(T data);
  10. }
  11.  
  12. abstract class B<V> implements A<Integer> {
  13. @Override
  14. public void a(Integer data) {
  15. // implementation
  16. }
  17.  
  18. @Handler
  19. public abstract void b(V data);
  20. }
  21.  
  22. class C extends B<String> {
  23. @Override
  24. public void b(String data) {
  25. // implementation
  26. }
  27. }
  28. /* Name of the class has to be "Main" only if the class is public. */
  29. class Ideone
  30. {
  31. public static void main(String[] args)
  32. {
  33. Set<Method> methods = getAnnotatedMethods(C.class, Handler.class);
  34. methods.forEach(System.out::println);
  35. }
  36. public static Set<Method> getAnnotatedMethods(
  37. Class<?> actualClass, Class<? extends Annotation> a) {
  38. Set<Method> raw = getRawAnnotatedMethods(actualClass, a);
  39. if(raw.isEmpty()) return raw;
  40. Set<Method> resolved = new HashSet<>();
  41. for(Method m: raw) {
  42. if(m.getDeclaringClass()==actualClass) resolved.add(m);
  43. else {
  44. Method x = getMoreSpecific(actualClass, m);
  45. resolved.add(!x.isBridge()? x: resolveGeneric(x, m));
  46. }
  47. }
  48. return resolved;
  49. }
  50. private static Method resolveGeneric(Method x, Method m) {
  51. final Class<?> decl = m.getDeclaringClass();
  52. Map<Type,Type> translate = new HashMap<>();
  53. up: for(Class<?> c=x.getDeclaringClass(); c!=decl; ) {
  54. if(decl.isInterface()) {
  55. for(Type t: c.getGenericInterfaces()) {
  56. Class<?> e = erased(t);
  57. if(updateMap(decl, e, t, translate)) continue;
  58. c = e;
  59. continue up;
  60. }
  61. }
  62. Type t = c.getGenericSuperclass();
  63. c = erased(t);
  64. updateMap(decl, c, t, translate);
  65. }
  66. Class<?>[] raw = m.getParameterTypes();
  67. Type[] generic = m.getGenericParameterTypes();
  68. for(int ix = 0; ix<raw.length; ix++)
  69. raw[ix] = erased(translate.getOrDefault(generic[ix], raw[ix]));
  70. return getMoreSpecific(x.getDeclaringClass(), x, raw);
  71. }
  72. private static Method getMoreSpecific(Class<?> actual, Method inherited) {
  73. return getMoreSpecific(actual, inherited, inherited.getParameterTypes());
  74. }
  75. private static Method getMoreSpecific(
  76. Class<?> actual, Method inherited, Class<?>[] pTypes) {
  77. try {
  78. final String name = inherited.getName();
  79. if(inherited.getDeclaringClass().isInterface()
  80. || Modifier.isPublic(inherited.getModifiers())) {
  81. return actual.getMethod(name, pTypes);
  82. }
  83. for(;;) try {
  84. return actual.getDeclaredMethod(name, pTypes);
  85. }
  86. actual = actual.getSuperclass();
  87. if(actual == null) throw ex;
  88. }
  89. }
  90. throw new IllegalStateException(ex);
  91. }
  92. }
  93.  
  94. private static boolean updateMap(Class<?> decl, Class<?> e, Type t, Map<Type, Type> m) {
  95. if (!decl.isAssignableFrom(e)) {
  96. return true;
  97. }
  98. if(t!=e) {
  99. TypeVariable<?>[] tp = e.getTypeParameters();
  100. if(tp.length>0) {
  101. Type[] arg = ((ParameterizedType)t).getActualTypeArguments();
  102. for(int ix=0; ix<arg.length; ix++)
  103. m.put(tp[ix], erased(m.getOrDefault(arg[ix], arg[ix])));
  104. }
  105. }
  106. return false;
  107. }
  108. private static Class<?> erased(Type t) {
  109. if(t instanceof Class<?>) return (Class<?>)t;
  110. if(t instanceof ParameterizedType)
  111. return (Class<?>)((ParameterizedType)t).getRawType();
  112. if(t instanceof TypeVariable<?>) return erased(((TypeVariable<?>)t).getBounds()[0]);
  113. if(t instanceof GenericArrayType) return Array.newInstance(
  114. erased(((GenericArrayType)t).getGenericComponentType()), 0).getClass();
  115. return erased(((WildcardType)t).getUpperBounds()[0]);
  116. }
  117. /**
  118.   * You may replace this with the MethodUtils.getMethodsListWithAnnotation()
  119.   * you were already using.
  120.   */
  121. private static Set<Method> getRawAnnotatedMethods(
  122. Class<?> c, Class<? extends Annotation> a) {
  123. Set<Method> s = new HashSet<>();
  124. for(; c!=null; c=c.getSuperclass()) {
  125. for(Method m: c.getDeclaredMethods()) {
  126. if(m.isAnnotationPresent(a)) s.add(m);
  127. }
  128. for(Class<?> ifC: c.getInterfaces()) {
  129. for(Method m: ifC.getMethods()) {
  130. if(m.isAnnotationPresent(a)) s.add(m);
  131. }
  132. }
  133. }
  134. return s;
  135. }
  136. }
  137.  
  138.  
Success #stdin #stdout 0.22s 2841600KB
stdin
Standard input is empty
stdout
public void C.b(java.lang.String)
public void B.a(java.lang.Integer)