package org.kevoree.api.helper;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
/**
*
* Java reflection utility class
*/
public class ReflectUtils {
/**
* Look for the annotationType in the class or one of its ancestors.
*
* @param clazz The class to scan.
* @param annotationType The annotation type to find.
* @return The annotation, null if not found.
*/
public static <T extends Annotation> T findAnnotation(Class<?> clazz, Class<T> annotationType) {
T a = clazz.getAnnotation(annotationType);
if (a != null) {
return a;
}
Class<?> parentClass = clazz.getSuperclass();
if (parentClass != null && !parentClass.equals(Object.class)) {
a = findAnnotation(parentClass, annotationType);
}
if (a == null) {
for (Class<?> i : clazz.getInterfaces()) {
a = findAnnotation(i, annotationType);
if (a != null) {
return a;
}
}
}
return a;
}
/**
* Look for a field based on his name and a given Annotation in a class.
*
* @param fieldName The field name.
* @param clazz The scanned class.
* @param annotationType The expected annotation type.
* @return The field if found, null if not.
*/
public static Field findFieldWithAnnotation(String fieldName, Class<?> clazz, Class<? extends Annotation> annotationType) {
Field field = getField(fieldName, clazz);
if (field != null) {
for (Annotation anno : field.getDeclaredAnnotations()) {
if (anno.annotationType().getName().equals(annotationType.getName())) {
return field;
}
}
}
return null;
}
/**
*
* @param clazz The class
* @param annotationTypes The annotation types expected
* @return True if one of the given annotation types is found, False otherwise
*/
public static boolean hasAnnotation(Class<?> clazz, Class<? extends Annotation>... annotationTypes) {
for (Class<? extends Annotation> anno : annotationTypes) {
if (findAnnotation(clazz, anno) != null) {
return true;
}
}
return false;
}
/**
* Find a field with the given name and class annotation
*
* @param fieldName The field name
* @param clazz The annotation class.
* @return the field, null if not found.
*/
public static Field getField(String fieldName, Class<?> clazz) {
List<Field> fields = getAllFields(clazz);
for (Field field : fields) {
if (field.getName().equals(fieldName)) {
return field;
}
}
return null;
}
/**
* Return all fields of the class, including inherited one.
*
* @param clazz The class.
* @return The list of all fields.
*/
public static List<Field> getAllFields(Class<?> clazz) {
List<Field> currentClassFields = new ArrayList<Field>(Arrays.asList(clazz.getDeclaredFields()));
Class<?> parentClass = clazz.getSuperclass();
if (parentClass != null && !(parentClass.equals(Object.class))) {
List<Field> parentClassFields = getAllFields(parentClass);
currentClassFields.addAll(parentClassFields);
}
return currentClassFields;
}
/**
* Return all fields of the class if annotated with the given type.
*
* @param clazz The class.
* @param annotationType The expected annotation type.
* @return The list of fields.
*/
public static List<Field> getAllFieldsWithAnnotation(final Class<?> clazz, final Class<? extends Annotation> annotationType) {
final List<Field> ret = new ArrayList<Field>();
for(Field f: getAllFields(clazz)) {
if(f.isAnnotationPresent(annotationType)) {
ret.add(f);
}
}
return ret;
}
/**
* Return all fields of the class if annotated
*
* @param clazz The class.
* @param annotationTypes The annotation types
* @return The list of fields.
*/
public static List<Field> getAllFieldsWithAnnotations(Class<?> clazz, List<Class<? extends Annotation>> annotationTypes) {
List<Field> fields = new ArrayList<Field>();
for (Class<? extends Annotation> annotationType : annotationTypes) {
fields.addAll(getAllFieldsWithAnnotation(clazz, annotationType));
}
return fields;
}
/**
* Return all fields of the class if annotated
*
* @param clazz The class.
* @param annotationTypes The annotation types
* @return The list of fields.
*/
public static List<Field> getAllFieldsWithAnnotations(Class<?> clazz, Class<? extends Annotation>... annotationTypes) {
return getAllFieldsWithAnnotations(clazz, Arrays.asList(annotationTypes));
}
/**
* Returns a Method annotated with the given Annotation class
*
* @param clazz the target object class
* @param annoClass the annotation class that you are looking for
* @return the annotated method if any; null otherwise
*/
public static Method findMethodWithAnnotation(final Class<?> clazz, final Class<? extends Annotation> annoClass) {
Method method;
for (Method metLoop : clazz.getDeclaredMethods()) {
if (metLoop.getAnnotation(annoClass) != null) {
method = metLoop;
return method;
}
}
if (clazz.getSuperclass() != null) {
method = findMethodWithAnnotation(clazz.getSuperclass(), annoClass);
if (method != null) {
return method;
}
}
for (Class<?> iClazz : clazz.getInterfaces()) {
method = findMethodWithAnnotation(iClazz, annoClass);
if (method != null) {
return method;
}
}
return null;
}
/**
* Returns a set of Methods annotated with the given Annotation class
*
* @param clazz the target object class
* @param annoClass the annotation class that you are looking for
* @return the annotated methods if any; empty set otherwise
*/
public static Set<Method> findMethodsWithAnnotation(final Class<?> clazz, final Class<? extends Annotation> annoClass) {
Set<Method> methods = new HashSet<Method>();
for (Method method : clazz.getDeclaredMethods()) {
if (method.getAnnotation(annoClass) != null) {
methods.add(method);
}
}
if (clazz.getSuperclass() != null) {
methods.addAll(findMethodsWithAnnotation(clazz.getSuperclass(), annoClass));
}
for (Class<?> iClazz : clazz.getInterfaces()) {
methods.addAll(findMethodsWithAnnotation(iClazz, annoClass));
}
return methods;
}
/**
* Returns the first occurence of a method based on its name and the given Annotation class
*
* @param clazz the target object class
* @param methodName the method name
* @param annoClass the annotation class that you are looking for
* @return the annotated method if any; null otherwise
*/
public static Method findMethodWithAnnotation(final Class<?> clazz, final String methodName,
final Class<? extends Annotation> annoClass) {
for (Method method : clazz.getDeclaredMethods()) {
if (method.getAnnotation(annoClass) != null && method.getName().equals(methodName)) {
return method;
}
}
if (clazz.getSuperclass() != null) {
Method method = findMethodWithAnnotation(clazz.getSuperclass(), methodName, annoClass);
if (method != null) {
return method;
}
}
for (Class<?> iClazz : clazz.getInterfaces()) {
Method method = findMethodWithAnnotation(iClazz, methodName, annoClass);
if (method != null) {
return method;
}
}
return null;
}
}