@Nullable
  public static Type resolveVariable(
      TypeVariable variable, final Class classType, boolean resolveInInterfacesOnly) {
    final Class aClass = getRawType(classType);
    int index = ArrayUtilRt.find(ReflectionCache.getTypeParameters(aClass), variable);
    if (index >= 0) {
      return variable;
    }

    final Class[] classes = ReflectionCache.getInterfaces(aClass);
    final Type[] genericInterfaces = ReflectionCache.getGenericInterfaces(aClass);
    for (int i = 0; i <= classes.length; i++) {
      Class anInterface;
      if (i < classes.length) {
        anInterface = classes[i];
      } else {
        anInterface = ReflectionCache.getSuperClass(aClass);
        if (resolveInInterfacesOnly || anInterface == null) {
          continue;
        }
      }
      final Type resolved = resolveVariable(variable, anInterface);
      if (resolved instanceof Class || resolved instanceof ParameterizedType) {
        return resolved;
      }
      if (resolved instanceof TypeVariable) {
        final TypeVariable typeVariable = (TypeVariable) resolved;
        index = ArrayUtilRt.find(ReflectionCache.getTypeParameters(anInterface), typeVariable);
        if (index < 0) {
          LOG.error(
              "Cannot resolve type variable:\n"
                  + "typeVariable = "
                  + typeVariable
                  + "\n"
                  + "genericDeclaration = "
                  + declarationToString(typeVariable.getGenericDeclaration())
                  + "\n"
                  + "searching in "
                  + declarationToString(anInterface));
        }
        final Type type =
            i < genericInterfaces.length ? genericInterfaces[i] : aClass.getGenericSuperclass();
        if (type instanceof Class) {
          return Object.class;
        }
        if (type instanceof ParameterizedType) {
          return getActualTypeArguments((ParameterizedType) type)[index];
        }
        throw new AssertionError("Invalid type: " + type);
      }
    }
    return null;
  }
 @Nullable
 public static Class<?> substituteGenericType(final Type genericType, final Type classType) {
   if (genericType instanceof TypeVariable) {
     final Class<?> aClass = getRawType(classType);
     final Type type = resolveVariable((TypeVariable) genericType, aClass);
     if (type instanceof Class) {
       return (Class) type;
     }
     if (type instanceof ParameterizedType) {
       return (Class<?>) ((ParameterizedType) type).getRawType();
     }
     if (type instanceof TypeVariable && classType instanceof ParameterizedType) {
       final int index = ArrayUtilRt.find(ReflectionCache.getTypeParameters(aClass), type);
       if (index >= 0) {
         return getRawType(getActualTypeArguments((ParameterizedType) classType)[index]);
       }
     }
   } else {
     return getRawType(genericType);
   }
   return null;
 }