code: public static Map<TypeVariable, Type> matchVariables(final Type template, final Type real) {
          final MatchVariablesVisitor visitor = new MatchVariablesVisitor();
          TypesWalker.walk(template, real, visitor);
          if (visitor.isHierarchyError()) {
              throw new IllegalArgumentException(String.format(
                      "Type %s variables can't be matched from type %s because they "
                              + "are not compatible",
                      TypeToStringUtils.toStringTypeIgnoringVariables(template),
                      TypeToStringUtils.toStringTypeIgnoringVariables(real)));
          }
          final Map<TypeVariable, Type> res = visitor.getMatched();
          // to be sure that right type does not contain variables
          for (Map.Entry<TypeVariable, Type> entry : res.entrySet()) {
              entry.setValue(resolveAllTypeVariables(entry.getValue(), visitor.getMatchedMap()));
          }
          return res;
      }
docs: Match explicit variables ({@link ExplicitTypeVariable}) in type with provided type. For example, suppose
  you have type {@code List<E>} (with {@link ExplicitTypeVariable} as E variable) and
  real type {@code List<String>}. This method will match variable E to String from real type.
  <p>
  WARNING: if provided template type will contain {@link TypeVariable} - they would not be detected!
  Because method resolve all variables to it's raw declaration. Use {@link #preserveVariables(Type)} in order
  to replace variables before matching. It is not dont automatically to avoid redundant calls (this api
  considered as low level api).
  
  @param template type with variables
  @param real     type to compare and resolve variables from
  @return map of resolved variables or empty map
  @throws IllegalArgumentException when provided types are nto compatible
  @see #trackRootVariables(Class, List) for variables tracking form root class
  @see #preserveVariables(Type) for variables preserving in types