package org.zstack.utils;
import com.googlecode.gentyref.GenericTypeReflector;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;
public class FieldUtils {
public static <T> T getFieldValue(String name, Object obj) {
Field f = getField(name, obj.getClass());
if (f == null) {
return null;
}
try {
f.setAccessible(true);
Object val = f.get(obj);
return (T)val;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static boolean hasField(String name, Class clazz) {
return getField(name, clazz) != null;
}
public static Field getField(String name, Class<?> clazz) {
do {
try {
Field f = clazz.getDeclaredField(name);
return f;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
} catch (SecurityException e) {
throw new RuntimeException(e);
}
} while (clazz != Object.class);
return null;
}
public static List<Field> getAllFields(Class<?> clazz) {
List<Field> fields = new ArrayList<Field>();
do {
Field[] fs = clazz.getDeclaredFields();
Collections.addAll(fields, fs);
clazz = clazz.getSuperclass();
} while (clazz != Object.class);
return fields;
}
public static Field getAnnotatedField(Class annotation, Class clazz) {
do {
Field[] fs = clazz.getDeclaredFields();
for (Field f : fs) {
if (f.isAnnotationPresent(annotation)) {
return f;
}
}
clazz = clazz.getSuperclass();
} while (clazz != Object.class);
return null;
}
public static Field getAnnotatedFieldOfThisClass(Class annotation, Class clazz) {
Field[] fs = clazz.getDeclaredFields();
for (Field f : fs) {
if (f.isAnnotationPresent(annotation)) {
return f;
}
}
return null;
}
public static List<Class> getAllSuperClasses(Class self, Class stopBy) {
if (stopBy == null) {
stopBy = Object.class;
}
if (!stopBy.isAssignableFrom(self)) {
throw new RuntimeException(String.format("class[%s] is not ancient class of class[%s]", stopBy.getName(), self.getName()));
}
List<Class> ret = new ArrayList<Class>();
while (self != stopBy) {
self = self.getSuperclass();
ret.add(self);
}
return ret;
}
public static List<Class> getAllSuperClasses(Class self) {
return getAllSuperClasses(self, null);
}
public static List<Field> getTypeAnnotatedFields(Class annotation, Class clazz) {
List<Field> ret = new ArrayList<Field>();
do {
Field[] fs = clazz.getDeclaredFields();
for (Field f : fs) {
if (f.getType().isAnnotationPresent(annotation)) {
ret.add(f);
}
}
clazz = clazz.getSuperclass();
} while (clazz != Object.class);
return ret;
}
public static List<Field> getTypeAnnotatedFieldsOnThisClass(Class annotation, Class clazz) {
List<Field> ret = new ArrayList<Field>();
Field[] fs = clazz.getDeclaredFields();
for (Field f : fs) {
if (f.getType().isAnnotationPresent(annotation)) {
ret.add(f);
}
}
return ret;
}
public static List<Field> getAnnotatedFields(Class annotation, Class clazz) {
List<Field> ret = new ArrayList<Field>();
do {
Field[] fs = clazz.getDeclaredFields();
for (Field f : fs) {
if (f.isAnnotationPresent(annotation)) {
ret.add(f);
}
}
clazz = clazz.getSuperclass();
} while (clazz != Object.class);
return ret;
}
public static List<Field> getAnnotatedFieldsOnThisClass(Class annotation, Class clazz) {
List<Field> ret = new ArrayList<Field>();
Field[] fs = clazz.getDeclaredFields();
for (Field f : fs) {
if (f.isAnnotationPresent(annotation)) {
ret.add(f);
}
}
return ret;
}
public static Class getGenericType(Field field) {
Class type = field.getType();
if (!Collection.class.isAssignableFrom(type) && !Map.class.isAssignableFrom(type)) {
throw new IllegalArgumentException(String.format("only Collection and Map can get generic type at runtime, field[name:%s] is %s",
field.getName(), type.getName()));
}
try {
Type gtype = field.getGenericType();
if (!(gtype instanceof ParameterizedType)) {
return null;
}
Type[] gtypes = ((ParameterizedType)gtype).getActualTypeArguments();
if (gtypes.length == 0) {
return null;
}
Type ret = null;
if (Collection.class.isAssignableFrom(type)) {
ret = gtypes[0];
} else {
ret = gtypes[1];
}
if (ret instanceof Class) {
return (Class) ret;
} else {
return null;
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static GenericType inferMap(Type type) {
MapGenericType ret = new MapGenericType();
Type keyType = GenericTypeReflector.getTypeParameter(type, Map.class.getTypeParameters()[0]);
Type valueType = GenericTypeReflector.getTypeParameter(type, Map.class.getTypeParameters()[1]);
ret.isInferred = keyType != null && valueType != null;
if (keyType == null || valueType == null) {
return ret;
}
ret.keyType = GenericTypeReflector.erase(keyType);
ret.valueType = GenericTypeReflector.erase(valueType);
if (!ret.isInferred) {
return ret;
}
if (Map.class.isAssignableFrom(ret.keyType)) {
ret.nestedGenericKey = inferMap(keyType);
} else if (Collection.class.isAssignableFrom(ret.keyType)) {
ret.nestedGenericKey = inferCollection(keyType);
}
if (Map.class.isAssignableFrom(ret.valueType)) {
ret.nestedGenericValue = inferMap(valueType);
} else if (Collection.class.isAssignableFrom(ret.valueType)) {
ret.nestedGenericValue = inferCollection(valueType);
}
return ret;
}
private static GenericType inferCollection(Type type) {
CollectionGenericType ret = new CollectionGenericType();
Type valueType = GenericTypeReflector.getTypeParameter(type, Collection.class.getTypeParameters()[0]);
ret.isInferred = valueType != null;
if (valueType == null) {
return ret;
}
ret.valueType = GenericTypeReflector.erase(valueType);
if (Map.class.isAssignableFrom(ret.valueType)) {
ret.nestedGenericValue = inferMap(valueType);
} else if (Collection.class.isAssignableFrom(ret.valueType)) {
ret.nestedGenericValue = inferCollection(valueType);
}
return ret;
}
public static GenericType inferGenericTypeOnMapOrCollectionField(Field field) {
Class owner = field.getDeclaringClass();
Type t = GenericTypeReflector.getExactFieldType(field, owner);
if (Map.class.isAssignableFrom(field.getType())) {
return inferMap(t);
} else if (Collection.class.isAssignableFrom(field.getType())) {
return inferCollection(t);
} else {
throw new IllegalArgumentException(String.format("field is type of %s, only Map or Collection field can be inferred", field.getType().getName()));
}
}
public static interface GenericType {
boolean isMap();
boolean isCollection();
boolean isInferred();
<T> T cast();
}
public static class MapGenericType implements GenericType {
private boolean isInferred;
private Class keyType;
private Class valueType;
private GenericType nestedGenericValue;
private GenericType nestedGenericKey;
public Class getKeyType() {
return keyType;
}
public void setKeyType(Class keyType) {
this.keyType = keyType;
}
public Class getValueType() {
return valueType;
}
public void setValueType(Class valueType) {
this.valueType = valueType;
}
public GenericType getNestedGenericValue() {
return nestedGenericValue;
}
public void setNestedGenericValue(GenericType nestedGenericValue) {
this.nestedGenericValue = nestedGenericValue;
}
public GenericType getNestedGenericKey() {
return nestedGenericKey;
}
public void setNestedGenericKey(GenericType nestedGenericKey) {
this.nestedGenericKey = nestedGenericKey;
}
@Override
public boolean isMap() {
return true;
}
@Override
public boolean isCollection() {
return false;
}
@Override
public boolean isInferred() {
return isInferred;
}
@Override
public <T> T cast() {
return (T)this;
}
public void setInferred(boolean isInferred) {
this.isInferred = isInferred;
}
}
public static class CollectionGenericType implements GenericType {
private Class valueType;
private boolean isInferred;
private GenericType nestedGenericValue;
public Class getValueType() {
return valueType;
}
public void setValueType(Class valueType) {
this.valueType = valueType;
}
@Override
public boolean isMap() {
return false;
}
@Override
public boolean isCollection() {
return true;
}
@Override
public boolean isInferred() {
return isInferred;
}
@Override
public <T> T cast() {
return (T)this;
}
public void setInferred(boolean isInferred) {
this.isInferred = isInferred;
}
public GenericType getNestedGenericValue() {
return nestedGenericValue;
}
public void setNestedGenericValue(GenericType nestedGenericValue) {
this.nestedGenericValue = nestedGenericValue;
}
}
}