package by.istin.android.xcore.utils;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import by.istin.android.xcore.annotations.dbEntities;
import by.istin.android.xcore.annotations.dbEntity;
public class ReflectUtils {
private static class XClass {
private Class<?> clazz;
private XClass(Class<?> clazz) {
this.clazz = clazz;
}
private final Object lock = new Object();
private List<XField> listFields;
private final Map<XClass, Holder> instancesOfInterface = new ConcurrentHashMap<XClass, Holder>();
public List<XField> getFields() {
if (listFields == null) {
synchronized (lock) {
if (listFields == null) {
listFields = new ArrayList<XField>();
Field[] fields = clazz.getFields();
for (Field field : fields) {
Annotation[] annotations = field.getAnnotations();
if (field.getType().equals(String.class) && Modifier.isStatic(field.getModifiers()) && annotations != null && annotations.length != 0) {
//we need be sure that all sub entities insert after parent
XField xField = new XField(field);
if (ReflectUtils.isAnnotationPresent(xField, dbEntity.class) || ReflectUtils.isAnnotationPresent(xField, dbEntities.class)) {
listFields.add(xField);
} else {
listFields.add(0, xField);
}
}
}
}
}
}
return listFields;
}
public <T> T getInstanceInterface(Class<T> interfaceTargetClazz) {
try {
XClass xInterfaceClass = getXClass(interfaceTargetClazz);
Holder<T> result = (Holder<T>) instancesOfInterface.get(xInterfaceClass);
if (result == null) {
synchronized (lock) {
result = (Holder<T>) instancesOfInterface.get(xInterfaceClass);
if (result == null && !instancesOfInterface.containsKey(xInterfaceClass)) {
Class<?> cls = clazz;
while (cls != null) {
Class<?>[] interfaces = cls.getInterfaces();
for (Class<?> i : interfaces) {
if (i.equals(interfaceTargetClazz)) {
T object = (T) clazz.newInstance();
instancesOfInterface.put(xInterfaceClass, new Holder<T>(object));
return object;
}
}
cls = cls.getSuperclass();
}
}
result = new Holder<T>();
instancesOfInterface.put(xInterfaceClass, result);
}
}
return result.get();
} catch (Exception e) {
return null;
}
}
}
public static class XField {
private final Field mField;
private final String mNameOfField;
private final HashSet<Class<? extends Annotation>> mAnnotations = new HashSet<Class<? extends Annotation>>();
private final Map<Class<? extends Annotation>, Annotation> mClassAnnotationHashMap = new ConcurrentHashMap<Class<? extends Annotation>, Annotation>();
XField(Field field) {
mField = field;
//init name of field
mField.setAccessible(true);
try {
mNameOfField = (String)mField.get(null);
} catch (IllegalAccessException e) {
throw new IllegalArgumentException(e);
}
mField.setAccessible(false);
//init annotations
Annotation[] annotations = mField.getAnnotations();
if (annotations != null) {
for (Annotation annotation : annotations) {
Class<? extends Annotation> annotationType = annotation.annotationType();
mAnnotations.add(annotationType);
mClassAnnotationHashMap.put(annotationType, annotation);
}
}
}
public Field getField() {
return mField;
}
public String getNameOfField() {
return mNameOfField;
}
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
return mAnnotations.contains(annotationClass);
}
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
return (T) mClassAnnotationHashMap.get(annotationClass);
}
}
private static final Map<Class<?>, XClass> sClassesCache = new ConcurrentHashMap<Class<?>, XClass>();
public static <T extends Annotation> T getAnnotation(XField field, Class<T> annotationClass) {
return field.getAnnotation(annotationClass);
}
public static List<XField> getEntityKeys(Class<?> clazz) {
return getXClass(clazz).getFields();
}
private static XClass getXClass(Class<?> clazz) {
XClass xClass = sClassesCache.get(clazz);
if (xClass == null) {
xClass = new XClass(clazz);
sClassesCache.put(clazz, xClass);
}
return xClass;
}
public static boolean isAnnotationPresent(XField field, Class<? extends Annotation> annotationClass) {
return field.isAnnotationPresent(annotationClass);
}
public static String getStaticStringValue(XField field) {
return field.getNameOfField();
}
public static Class<?> classForName(String className) {
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException(e);
}
}
//TODO move common logic to XClass
public static <T> T getInstanceInterface(Class<?> clazz, Class<T> interfaceTargetClazz) {
XClass xClass = getXClass(clazz);
return xClass.getInstanceInterface(interfaceTargetClazz);
}
public static <T> T newInstance(Class<T> clazz) {
try {
return clazz.newInstance();
} catch (InstantiationException e) {
throw new IllegalArgumentException(e);
} catch (IllegalAccessException e) {
throw new IllegalArgumentException(e);
}
}
}