code: public static Type unrollVariables(Map<TypeVariable<?>, Type> typeArguments, final Type type) {
          if (typeArguments == null) {
              typeArguments = Collections.emptyMap();
          }
          if (containsTypeVariables(type)) {
              if (type instanceof TypeVariable<?>) {
                  return unrollVariables(typeArguments, typeArguments.get(type));
              }
              if (type instanceof ParameterizedType) {
                  final ParameterizedType p = (ParameterizedType) type;
                  final Map<TypeVariable<?>, Type> parameterizedTypeArguments;
                  if (p.getOwnerType() == null) {
                      parameterizedTypeArguments = typeArguments;
                  } else {
                      parameterizedTypeArguments = new HashMap<>(typeArguments);
                      parameterizedTypeArguments.putAll(TypeUtils.getTypeArguments(p));
                  }
                  final Type[] args = p.getActualTypeArguments();
                  for (int i = 0; i < args.length; i++) {
                      final Type unrolled = unrollVariables(parameterizedTypeArguments, args[i]);
                      if (unrolled != null) {
                          args[i] = unrolled;
                      }
                  }
                  return parameterizeWithOwner(p.getOwnerType(), (Class<?>) p.getRawType(), args);
              }
              if (type instanceof WildcardType) {
                  final WildcardType wild = (WildcardType) type;
                  return wildcardType().withUpperBounds(unrollBounds(typeArguments, wild.getUpperBounds()))
                      .withLowerBounds(unrollBounds(typeArguments, wild.getLowerBounds())).build();
              }
          }
          return type;
      }
docs: Get a type representing {@code type} with variable assignments "unrolled."
  
  @param typeArguments as from {@link TypeUtils#getTypeArguments(Type, Class)}
  @param type the type to unroll variable assignments for
  @return Type
  @since 3.2