If the expected type is a subtype of {@link Map}, the resolved super type is returned.
This allows to query for the type arguments that are available on the expectation.
2500
protected LightweightTypeReference getMapExpectation(LightweightTypeReference expectation) {
		if (expectation != null && expectation.isResolved()) {
			LightweightTypeReference result = expectation.getSuperType(Map.class);
			if (result != null && result.getTypeArguments().size() == 2) {
				return result;
			}
		}
		return null;
	}
158737
public void assertEqualMappedBy(Function<? super E, ?> expectedMapper, Function<? super A, ?> actualMapper) {
		if (!isEqualMappedBy(expectedMapper, actualMapper)) {
			throwAssertionError();
		}
	}
968683
private Class<?> resolveClass(Type type) {
    if (type instanceof Class) {
      return (Class<?>) type;
    } else if (type instanceof ParameterizedType) {
      return resolveClass(((ParameterizedType) type).getRawType());
    } else if (type instanceof WildcardType) {
      Type[] bounds = ((WildcardType) type).getUpperBounds();
      if (bounds.length > 0) {
        return (Class<?>) bounds[0];
      }
    }
    return null;
  }
1124729
Type resolveTypeVariables(final Type type) {
        if (type instanceof Class<?>) {
            // Arrays and non-generic classes have no type variables
            return type;

        } else if (type instanceof ParameterizedType) {
            // Recursively resolve parameterized types
            final ParameterizedType parameterizedType = (ParameterizedType) type;
            final Type[] typeArgs = parameterizedType.getActualTypeArguments();
            Type[] typeArgsResolved = null;
            for (int i = 0; i < typeArgs.length; i++) {
                // Recursively revolve each parameter of the type
                final Type typeArgResolved = resolveTypeVariables(typeArgs[i]);
                // Only compare typeArgs to typeArgResolved until the first difference is found
                if (typeArgsResolved == null) {
                    if (!typeArgResolved.equals(typeArgs[i])) {
                        // After the first difference is found, lazily allocate typeArgsResolved 
                        typeArgsResolved = new Type[typeArgs.length];
                        // Go back and copy all the previous args
                        System.arraycopy(typeArgs, 0, typeArgsResolved, 0, i);
                        // Insert the first different arg
                        typeArgsResolved[i] = typeArgResolved;
                    }
                } else {
                    // After the first difference is found, keep copying the resolved args into the array 
                    typeArgsResolved[i] = typeArgResolved;
                }
            }
            if (typeArgsResolved == null) {
                // There were no type parameters to resolve
                return type;
            } else {
                // Return new ParameterizedType that wraps the resolved type args
                return new ParameterizedTypeImpl((Class<?>) parameterizedType.getRawType(), typeArgsResolved,
                        parameterizedType.getOwnerType());
            }

        } else if (type instanceof TypeVariable<?>) {
            // Look up concrete type for type variable
            final TypeVariable<?> typeVariable = (TypeVariable<?>) type;
            for (int i = 0; i < typeVariables.length; i++) {
                if (typeVariables[i].getName().equals(typeVariable.getName())) {
                    return resolvedTypeArguments[i];
                }
            }
            // Could not resolve type variable
            return type;

        } else if (type instanceof GenericArrayType) {
            // Count the array dimensions, and resolve the innermost type of the array
            int numArrayDims = 0;
            Type t = type;
            while (t instanceof GenericArrayType) {
                numArrayDims++;
                t = ((GenericArrayType) t).getGenericComponentType();
            }
            final Type innermostType = t;
            final Type innermostTypeResolved = resolveTypeVariables(innermostType);
            if (!(innermostTypeResolved instanceof Class<?>)) {
                throw new IllegalArgumentException("Could not resolve generic array type " + type);
            }
            final Class<?> innermostTypeResolvedClass = (Class<?>) innermostTypeResolved;

            // Build an array to hold the size of each dimension, filled with zeroes
            final int[] dims = (int[]) Array.newInstance(int.class, numArrayDims);

            // Build a zero-sized array of the required number of dimensions, using the resolved innermost class 
            final Object arrayInstance = Array.newInstance(innermostTypeResolvedClass, dims);

            // Get the class of this array instance -- this is the resolved array type
            return arrayInstance.getClass();

        } else if (type instanceof WildcardType) {
            // TODO: Support WildcardType
            throw ClassGraphException.newClassGraphException("WildcardType not yet supported: " + type);

        } else {
            throw ClassGraphException.newClassGraphException("Got unexpected type: " + type);
        }
    }
1371969
@Override
	protected Map<JvmTypeParameter, LightweightMergedBoundTypeArgument> getTypeParameterMapping() {
		if (typeParameterMapping == null) {
			typeParameterMapping = initializeTypeParameterMapping();
		}
		return typeParameterMapping;
	}
221242
public boolean isSubtypeOf(JvmType type) {
		if (type == null) {
			throw new IllegalArgumentException("type may not be null");
		}
		// TODO interfaces don't inherit from non-interfaces, primitives, arrays, object
		// A final type does not have any subtypes
		// check for type == this.type
		LightweightTypeReference other = owner.toPlainTypeReference(type);
		boolean result = other.isAssignableFrom(this);
		return result;
	}
110558
public void computeType(XSetLiteral literal, ITypeComputationState state) {
		JvmGenericType setType = findDeclaredType(Set.class, state);
		if (setType == null) {
			handleCollectionTypeNotAvailable(literal, state, Set.class);
			return;
		}
		JvmGenericType mapType = findDeclaredType(Map.class, state);
		for(ITypeExpectation expectation: state.getExpectations()) {
			computeType(literal, setType, mapType, expectation, state);
		}
	}
34508
@SuppressWarnings({"PMD.AvoidProtectedMethodInFinalClassNotExtending",
            "PMD.CyclomaticComplexity",
            "checkstyle:CyclomaticComplexity"})
    protected static Type resolveTypeVariables(final Type type,
                                               final Map<String, Type> generics,
                                               final boolean countPreservedVariables) {
        Type resolvedGenericType = null;
        if (type instanceof TypeVariable) {
            // simple named generics resolved to target types
            resolvedGenericType = declaredGeneric((TypeVariable) type, generics);
        } else if (type instanceof ExplicitTypeVariable) {
            // special type used to preserve named generic (and differentiate from type variable)
            resolvedGenericType = declaredGeneric((ExplicitTypeVariable) type, generics, countPreservedVariables);
        } else if (type instanceof Class) {
            resolvedGenericType = type;
        } else if (type instanceof ParameterizedType) {
            // here parameterized type could shrink to class (if it has no arguments and owner class)
            resolvedGenericType = resolveParameterizedTypeVariables(
                    (ParameterizedType) type, generics, countPreservedVariables);
        } else if (type instanceof GenericArrayType) {
            // here generic array could shrink to array class (if component type shrink to simple class)
            resolvedGenericType = resolveGenericArrayTypeVariables(
                    (GenericArrayType) type, generics, countPreservedVariables);
        } else if (type instanceof WildcardType) {
            // here wildcard could shrink to upper type (if it has only one upper type)
            resolvedGenericType = resolveWildcardTypeVariables(
                    (WildcardType) type, generics, countPreservedVariables);
        }
        return resolvedGenericType;
    }
115099
public static boolean isTypeOrSubTypeOf(Type subType, Type superType) {
        Class<?> sub = getRawClass(subType);
        Class<?> sup = getRawClass(superType);

        return sup.isAssignableFrom(sub);
    }
1360791
public static Type resolve(Type type, Type declaringType, EntityType context) {
        Type resolved = unwrap(type);

        String varName = getVarName(resolved);
        if (varName != null) {
            resolved = resolveVar(resolved, varName, declaringType, context);
        } else if (!resolved.getParameters().isEmpty()) {
            resolved = resolveWithParameters(resolved, declaringType, context);
        }

        // rewrap entity type
        if (type instanceof EntityType) {
            if (!unwrap(type).equals(resolved)) {
                resolved = new EntityType(resolved, ((EntityType) type).getSuperTypes());
            } else {
                // reset to original type
                resolved = type;
            }
        }

        return resolved;
    }
299613
private SupertypeQueryResults computeSupertypes(ClassDescriptor classDescriptor) // throws
    // ClassNotFoundException
    {
        if (DEBUG_QUERIES) {
            System.out.println("Computing supertypes for " + classDescriptor.toDottedClassName());
        }

        // Try to fully resolve the class and its superclasses/superinterfaces.
        ClassVertex typeVertex = optionallyResolveClassVertex(classDescriptor);

        // Create new empty SupertypeQueryResults.
        SupertypeQueryResults supertypeSet = new SupertypeQueryResults();

        // Add all known superclasses/superinterfaces.
        // The ClassVertexes for all of them should be in the
        // InheritanceGraph by now.
        LinkedList<ClassVertex> workList = new LinkedList<>();
        workList.addLast(typeVertex);
        while (!workList.isEmpty()) {
            ClassVertex vertex = workList.removeFirst();
            supertypeSet.addSupertype(vertex.getClassDescriptor());
            if (vertex.isResolved()) {
                if (DEBUG_QUERIES) {
                    System.out.println("  Adding supertype " + vertex.getClassDescriptor().toDottedClassName());
                }
            } else {
                if (DEBUG_QUERIES) {
                    System.out.println("  Encountered unresolved class " + vertex.getClassDescriptor().toDottedClassName()
                            + " in supertype query");
                }
                supertypeSet.setEncounteredMissingClasses(true);
            }

            Iterator<InheritanceEdge> i = graph.outgoingEdgeIterator(vertex);
            while (i.hasNext()) {
                InheritanceEdge edge = i.next();
                workList.addLast(edge.getTarget());
            }
        }

        return supertypeSet;
    }
613092
public void addDefaultSuper(SuperTypeMapping mapping) {
		if (mapping != null) {
			this.superTypeMapping.put(mapping.getType(), mapping.getSuper());
		}
	}
393185
protected boolean isSubtypeButNotSynonym(LightweightTypeReference expectation, Class<?> clazz) {
		if (expectation.isType(clazz)) {
			return true;
		}
		ITypeReferenceOwner owner = expectation.getOwner();
		JvmType declaredType = owner.getServices().getTypeReferences().findDeclaredType(clazz, owner.getContextResourceSet());
		if (declaredType == null) {
			return false;
		}
		LightweightTypeReference superType = owner.newParameterizedTypeReference(declaredType);
		// don't allow synonyms, e.g. Iterable is not considered to be a supertype of Functions.Function0
		boolean result = superType.isAssignableFrom(expectation.getRawTypeReference(), 
				new TypeConformanceComputationArgument(false, false, true, true, false, false));
		return result;
	}
657396
@SuppressWarnings("unchecked")
	public <B, T extends B, D extends B> B resolveBeanWithDefaultClass(Class<T> typeToResolve, Class<D> defaultType) {

		// if type to resolve is null, do nothing, not even the default
		if(typeToResolve == null) {
			return null;
		}
		
		// get candidate resolve types
		Set<Bean<?>> candidates = this.manager.getBeans(typeToResolve);
		
		// if no candidates are available, resolve
		// using next class up
		if(!candidates.iterator().hasNext()) {
			this.logger.trace("No candidates for: {}", typeToResolve.getName());
			// try and resolve only the default type
			return resolveBeanWithDefaultClass(defaultType, null);
		} 
		
		this.logger.trace("Requesting resolution on: {}", typeToResolve.getName());
		
		// get candidate
		Bean<?> bean = candidates.iterator().next();
		CreationalContext<?> context = this.manager.createCreationalContext(bean);
		Type type = (Type) bean.getTypes().iterator().next();
	    B result = (B)this.manager.getReference(bean, type, context);
		
		this.logger.trace("Resolved to: {}", result.getClass().getName());
		
		return result;
	}
1296542
public void resolveType() {
        if (getTypeStyle() == null) {
            setTypeStyle("");
        }
        final String fieldType = getFieldType();
        String generics = "";
        if (fieldType.contains("<")) {
            generics = fieldType.substring(fieldType.indexOf('<'));
        }
        if (getTypeStyle().equals("smart")) {
            setType(fieldType);
        } else if (getTypeStyle().length() > 0) {
            if (getTypeStyle().contains("<>")) {
                setType(getTypeStyle().replace("<>", generics));
            } else if (getTypeStyle().contains("<")) {
                setType(getTypeStyle());
            } else {
                setType(getTypeStyle() + generics);
            }
        } else {
            setType(fieldType);
        }
    }
1084242
protected LightweightTypeReference createMapTypeReference(JvmGenericType mapType, LightweightTypeReference pairType, LightweightTypeReference expectation, ITypeReferenceOwner owner) {
		List<LightweightTypeReference> leftAndRight = pairType.getTypeArguments();
		
		LightweightTypeReference left = leftAndRight.get(0).getInvariantBoundSubstitute();
		LightweightTypeReference right = leftAndRight.get(1).getInvariantBoundSubstitute();
		
		LightweightTypeReference mapExpectation = getMapExpectation(expectation);
		if (mapExpectation != null) {
			List<LightweightTypeReference> typeArguments = expectation.getTypeArguments();
			left = doNormalizeElementType(left, typeArguments.get(0));
			right = doNormalizeElementType(right, typeArguments.get(1));
		}
		ParameterizedTypeReference result = owner.newParameterizedTypeReference(mapType);
		result.addTypeArgument(left.copyInto(owner));
		result.addTypeArgument(right.copyInto(owner));
		if (mapExpectation != null && !expectation.isAssignableFrom(result)) {
			// expectation does not match the computed type, but looks good according to the element types:
			// use expected type
			if (matchesExpectation(left, mapExpectation.getTypeArguments().get(0)) && matchesExpectation(right, mapExpectation.getTypeArguments().get(1))) {
				return expectation;
			}
		}
		return result;
	}
580871
public final Type getResultType() {
		Type type = resultTypeToken.getType();
		if (type instanceof Class || type instanceof ParameterizedType || type instanceof GenericArrayType) {
			return type;
		} else {
			throw new IllegalArgumentException("Cannot resolve result type: "+resultTypeToken);
		}
	}