*
* @param clazz A target class.
* @return A table of method and annnotations.
*/
public static Table<Method, Annotation> getAnnotations(Class clazz) {
Table<Method, Annotation> table = new Table();
for (Class type : ClassUtil.getTypes(clazz)) {
for (Method method : type.getDeclaredMethods()) {
// exclude the method which is created by compiler
// exclude the private method which is not declared in the specified class
if (!method.isBridge() && !method.isSynthetic() && (((method.getModifiers() & Modifier.PRIVATE) == 0) || method.getDeclaringClass() == clazz)) {
Annotation[] annotations = method.getAnnotations();
if (annotations.length != 0) {
List<Annotation> list = new ArrayList();
// disclose container annotation
for (Annotation annotation : annotations) {
try {
Class annotationType = annotation.annotationType();
Method value = annotationType.getMethod("value");
Class returnType = value.getReturnType();
if (returnType.isArray()) {
Class<?> componentType = returnType.getComponentType();
Repeatable repeatable = componentType.getAnnotation(Repeatable.class);
if (repeatable != null && repeatable.value() == annotationType) {
value.setAccessible(true);
Annotation[] items = (Annotation[]) value.invoke(annotation);
for (Annotation item : items) {
list.add(item);
}
continue;
}
}
} catch (Exception e) {
// do nothing
}
list.add(annotation);
}
// check method overriding
for (Method candidate : table.keySet()) {
if (candidate.getName().equals(method.getName()) && Arrays.deepEquals(candidate.getParameterTypes(), method.getParameterTypes())) {
method = candidate; // detect overriding
break;
}
}
add: for (Annotation annotation : list) {
Class annotationType = annotation.annotationType();
if (!annotationType.isAnnotationPresent(Repeatable.class)) {
for (Annotation item : table.get(method)) {
if (item.annotationType() == annotationType) {
continue add;
}
}
}
table.push(method, annotation);
}
}
}
}
}