Package com.alibaba.fastjson.util

Source Code of com.alibaba.fastjson.util.FieldInfo

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();
      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() //
          );
        }
      }
      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;
  }

}
TOP

Related Classes of com.alibaba.fastjson.util.FieldInfo

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.