package org.zbus.common.json.util; import java.lang.annotation.Annotation; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.GenericArrayType; import java.lang.reflect.GenericDeclaration; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import org.zbus.common.json.annotation.JSONField; public class FieldInfo implements Comparable<FieldInfo> { private final String name; private final Method method; private final Field field; private final Class<?> fieldClass; private final Type fieldType; private final Class<?> declaringClass; private boolean getOnly = false; public FieldInfo(String name, Class<?> declaringClass, Class<?> fieldClass, Type fieldType, Field field){ this.name = name; this.declaringClass = declaringClass; this.fieldClass = fieldClass; this.fieldType = fieldType; this.method = null; this.field = field; if (field != null) { field.setAccessible(true); } } public FieldInfo(String name, Method method, Field field){ this(name, method, field, null, null); } public FieldInfo(String name, Method method, Field field, Class<?> clazz, Type type){ this.name = name; this.method = method; this.field = field; if (method != null) { method.setAccessible(true); } if (field != null) { field.setAccessible(true); } Type fieldType; Class<?> fieldClass; if (method != null) { if (method.getParameterTypes().length == 1) { fieldClass = method.getParameterTypes()[0]; fieldType = method.getGenericParameterTypes()[0]; } else { fieldClass = method.getReturnType(); fieldType = method.getGenericReturnType(); getOnly = true; } this.declaringClass = method.getDeclaringClass(); } else { fieldClass = field.getType(); fieldType = field.getGenericType(); this.declaringClass = field.getDeclaringClass(); } if (clazz != null && fieldClass == Object.class && fieldType instanceof TypeVariable) { TypeVariable<?> tv = (TypeVariable<?>) fieldType; Type genericFieldType = getInheritGenericType(clazz, tv); if (genericFieldType != null) { this.fieldClass = TypeUtils.getClass(genericFieldType); this.fieldType = genericFieldType; return; } } Type genericFieldType = getFieldType(clazz, type, fieldType); if (genericFieldType != fieldType) { if (genericFieldType instanceof ParameterizedType) { fieldClass = TypeUtils.getClass(genericFieldType); } else if (genericFieldType instanceof Class) { fieldClass = TypeUtils.getClass(genericFieldType); } } this.fieldType = genericFieldType; this.fieldClass = fieldClass; } public static Type getFieldType(Class<?> clazz, Type type, Type fieldType) { if (clazz == null || type == null) { return fieldType; } if (fieldType instanceof GenericArrayType) { GenericArrayType genericArrayType = (GenericArrayType) fieldType; Type componentType = genericArrayType.getGenericComponentType(); Type componentTypeX = getFieldType(clazz, type, componentType); if (componentType != componentTypeX) { Type fieldTypeX = Array.newInstance(TypeUtils.getClass(componentTypeX), 0).getClass(); return fieldTypeX; } return fieldType; } if (!TypeUtils.isGenericParamType(type)) { return fieldType; } if (fieldType instanceof TypeVariable) { ParameterizedType paramType = (ParameterizedType) TypeUtils.getGenericParamType(type); Class<?> parameterizedClass = TypeUtils.getClass(paramType); TypeVariable<?> typeVar = (TypeVariable<?>) fieldType; for (int i = 0; i < parameterizedClass.getTypeParameters().length; ++i) { if (parameterizedClass.getTypeParameters()[i].getName().equals(typeVar.getName())) { fieldType = paramType.getActualTypeArguments()[i]; return fieldType; } } } if (fieldType instanceof ParameterizedType) { ParameterizedType parameterizedFieldType = (ParameterizedType) fieldType; Type[] arguments = parameterizedFieldType.getActualTypeArguments(); boolean changed = false; for (int i = 0; i < arguments.length; ++i) { Type feildTypeArguement = arguments[i]; if (feildTypeArguement instanceof TypeVariable) { TypeVariable<?> typeVar = (TypeVariable<?>) feildTypeArguement; if (type instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) type; for (int j = 0; j < clazz.getTypeParameters().length; ++j) { if (clazz.getTypeParameters()[j].getName().equals(typeVar.getName())) { arguments[i] = parameterizedType.getActualTypeArguments()[j]; changed = true; } } } } } if (changed) { fieldType = new ParameterizedTypeImpl(arguments, parameterizedFieldType.getOwnerType(), parameterizedFieldType.getRawType()); return fieldType; } } return fieldType; } public static Type getInheritGenericType(Class<?> clazz, TypeVariable<?> tv) { Type type = null; GenericDeclaration gd = tv.getGenericDeclaration(); do { type = clazz.getGenericSuperclass(); if (type == null) { return null; } if (type instanceof ParameterizedType) { ParameterizedType ptype = (ParameterizedType) type; if (ptype.getRawType() == gd) { TypeVariable<?>[] tvs = gd.getTypeParameters(); Type[] types = ptype.getActualTypeArguments(); for (int i = 0; i < tvs.length; i++) { if (tvs[i] == tv) return types[i]; } return null; } } clazz = TypeUtils.getClass(type); } while (type != null); return null; } public String toString() { return this.name; } public Class<?> getDeclaringClass() { return declaringClass; } public Class<?> getFieldClass() { return fieldClass; } public Type getFieldType() { return fieldType; } public String getName() { return name; } public Method getMethod() { return method; } public Field getField() { return field; } public int compareTo(FieldInfo o) { return this.name.compareTo(o.name); } public <T extends Annotation> T getAnnotation(Class<T> annotationClass) { T annotation = null; if (method != null) { annotation = method.getAnnotation(annotationClass); } if (annotation == null) { if (field != null) { annotation = field.getAnnotation(annotationClass); } } return annotation; } public String getFormat() { String format = null; JSONField annotation = getAnnotation(JSONField.class); if (annotation != null) { format = annotation.format(); if (format.trim().length() == 0) { format = null; } } return format; } public Object get(Object javaObject) throws IllegalAccessException, InvocationTargetException { if (method != null) { Object value = method.invoke(javaObject, new Object[0]); return value; } return field.get(javaObject); } public void set(Object javaObject, Object value) throws IllegalAccessException, InvocationTargetException { if (method != null) { method.invoke(javaObject, new Object[] { value }); return; } field.set(javaObject, value); } public void setAccessible(boolean flag) throws SecurityException { if (method != null) { method.setAccessible(flag); return; } field.setAccessible(flag); } public boolean isGetOnly() { return getOnly; } }