content: package com.alibaba.fastjson.util;
  
  import java.lang.annotation.Annotation;
  import java.lang.reflect.Field;
  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;
  
  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, Method method,
                       Field field){
          this.name = name;
          this.declaringClass = declaringClass;
          this.fieldClass = fieldClass;
          this.fieldType = fieldType;
          this.method = method;
          this.field = field;
  
          if (method != null) {
              method.setAccessible(true);
          }
  
          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 (!(type instanceof ParameterizedType)) {
              return fieldType;
          }
  
          if (fieldType instanceof TypeVariable) {
              ParameterizedType paramType = (ParameterizedType) type;
              TypeVariable<?> typeVar = (TypeVariable<?>) fieldType;
  
              for (int i = 0; i < clazz.getTypeParameters().length; ++i) {
                  if (clazz.getTypeParameters()[i].getName().equals(typeVar.getName())) {
                      fieldType = paramType.getActualTypeArguments()[i];
                      break;
                  }
              }
          }
  
          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 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;
      }
  
  }
  