@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;
  }
 public static Type resolveVariableInHierarchy(final TypeVariable variable, final Class aClass) {
   Type type;
   Class current = aClass;
   while ((type = resolveVariable(variable, current, false)) == null) {
     current = ReflectionCache.getSuperClass(current);
     if (current == null) {
       return null;
     }
   }
   if (type instanceof TypeVariable) {
     return resolveVariableInHierarchy((TypeVariable) type, aClass);
   }
   return type;
 }
 @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;
 }
 @Nullable
 public static Method getMethod(
     @NotNull Class aClass, @NonNls @NotNull String name, Class... parameters) {
   return findMethod(ReflectionCache.getMethods(aClass), name, parameters);
 }
 public static Type[] getActualTypeArguments(final ParameterizedType parameterizedType) {
   return ReflectionCache.getActualTypeArguments(parameterizedType);
 }