@Nullable
	public ArgType replaceTypeVariablesUsingMap(ArgType replaceType, Map<ArgType, ArgType> replaceMap) {
		if (replaceMap.isEmpty()) {
			return null;
		}
		if (replaceType.isGenericType()) {
			return replaceMap.get(replaceType);
		}
		if (replaceType.isArray()) {
			ArgType replaced = replaceTypeVariablesUsingMap(replaceType.getArrayElement(), replaceMap);
			if (replaced == null) {
				return null;
			}
			return ArgType.array(replaced);
		}

		ArgType wildcardType = replaceType.getWildcardType();
		if (wildcardType != null && wildcardType.containsTypeVariable()) {
			ArgType newWildcardType = replaceTypeVariablesUsingMap(wildcardType, replaceMap);
			if (newWildcardType == null) {
				return null;
			}
			return ArgType.wildcard(newWildcardType, replaceType.getWildcardBound());
		}

		if (replaceType.isGeneric()) {
			ArgType outerType = replaceType.getOuterType();
			if (outerType != null) {
				ArgType replacedOuter = replaceTypeVariablesUsingMap(outerType, replaceMap);
				if (replacedOuter == null) {
					return null;
				}
				ArgType innerType = replaceType.getInnerType();
				ArgType replacedInner = replaceTypeVariablesUsingMap(innerType, replaceMap);
				return ArgType.outerGeneric(replacedOuter, replacedInner == null ? innerType : replacedInner);
			}
			List<ArgType> genericTypes = replaceType.getGenericTypes();
			if (notEmpty(genericTypes)) {
				List<ArgType> newTypes = Utils.collectionMap(genericTypes, t -> {
					ArgType type = replaceTypeVariablesUsingMap(t, replaceMap);
					return type == null ? t : type;
				});
				return ArgType.generic(replaceType, newTypes);
			}
		}
		return null;
	}
@Test
	void replaceTypeVariablesUsingMap() {
		ArgType typeVar = genericType("T");
		ArgType listCls = object("java.util.List");
		Map<ArgType, ArgType> typeMap = Collections.singletonMap(typeVar, STRING);

		replaceTypeVar(typeVar, typeMap, STRING);
		replaceTypeVar(generic(listCls, typeVar), typeMap, generic(listCls, STRING));
		replaceTypeVar(array(typeVar), typeMap, array(STRING));
	}