All Downloads are FREE. Search and download functionalities are using the official Maven repository.

mockit.internal.reflection.GenericTypeReflection Maven / Gradle / Ivy

Go to download

JMockit is a Java toolkit for automated developer testing. It contains APIs for the creation of the objects to be tested, for mocking dependencies, and for faking external APIs; JUnit (4 & 5) and TestNG test runners are supported. It also contains an advanced code coverage tool.

There is a newer version: 1.49
Show newest version
/*
 * Copyright (c) 2006 Rogério Liesenfeld
 * This file is subject to the terms of the MIT license (see LICENSE.txt).
 */
package mockit.internal.reflection;

import java.lang.reflect.*;
import java.util.*;
import java.util.Map.*;
import javax.annotation.*;

public final class GenericTypeReflection
{
   @Nonnull private final Map typeParametersToTypeArguments;
   @Nonnull private final Map typeParametersToTypeArgumentNames;
   @Nonnull private final Class ownerType;
   private final boolean withSignatures;

   public GenericTypeReflection(@Nonnull Class ownerClass, @Nullable Type genericType)
   {
      this(ownerClass, genericType, true);
   }

   public GenericTypeReflection(@Nonnull Class ownerClass, @Nullable Type genericType, boolean withSignatures)
   {
      typeParametersToTypeArguments = new HashMap(4);
      typeParametersToTypeArgumentNames =
         withSignatures ? new HashMap(4) : Collections.emptyMap();
      ownerType = ownerClass;
      this.withSignatures = withSignatures;
      discoverTypeMappings(ownerClass, genericType);
   }

   private void discoverTypeMappings(@Nonnull Class rawType, @Nullable Type genericType)
   {
      if (genericType instanceof ParameterizedType) {
         addMappingsFromTypeParametersToTypeArguments(rawType, (ParameterizedType) genericType);
      }

      addGenericTypeMappingsForSuperTypes(rawType);
   }

   private void addGenericTypeMappingsForSuperTypes(@Nonnull Class rawType)
   {
      Type superType = rawType;

      while (superType instanceof Class && superType != Object.class) {
         Class superClass = (Class) superType;
         superType = superClass.getGenericSuperclass();

         if (superType != null && superType != Object.class) {
            superClass = addGenericTypeMappingsIfParameterized(superType);
            superType = superClass;
         }

         addGenericTypeMappingsForInterfaces(superClass);
      }
   }

   @Nonnull
   private Class addGenericTypeMappingsIfParameterized(@Nonnull Type superType)
   {
      if (superType instanceof ParameterizedType) {
         ParameterizedType genericSuperType = (ParameterizedType) superType;
         Class rawType = (Class) genericSuperType.getRawType();
         addMappingsFromTypeParametersToTypeArguments(rawType, genericSuperType);
         return rawType;
      }

      return (Class) superType;
   }

   private void addGenericTypeMappingsForInterfaces(@Nonnull Class classOrInterface)
   {
      for (Type implementedInterface : classOrInterface.getGenericInterfaces()) {
         Class implementedType = addGenericTypeMappingsIfParameterized(implementedInterface);
         addGenericTypeMappingsForInterfaces(implementedType);
      }
   }

   private void addMappingsFromTypeParametersToTypeArguments(
      @Nonnull Class rawType, @Nonnull ParameterizedType genericType)
   {
      String ownerTypeDesc = getOwnerClassDesc(rawType);
      TypeVariable[] typeParameters = rawType.getTypeParameters();
      Type[] typeArguments = genericType.getActualTypeArguments();

      for (int i = 0, n = typeParameters.length; i < n; i++) {
         TypeVariable typeParam = typeParameters[i];
         String typeVarName = typeParam.getName();

         if (typeParametersToTypeArguments.containsKey(ownerTypeDesc + ':' + typeVarName)) {
            continue;
         }

         Type typeArg = typeArguments[i];

         if (typeArg instanceof Class) {
            addMappingForClassType(ownerTypeDesc, typeVarName, typeArg);
         }
         else if (typeArg instanceof TypeVariable) {
            addMappingForTypeVariable(ownerTypeDesc, typeVarName, typeArg);
         }
         else if (typeArg instanceof ParameterizedType) {
            addMappingForParameterizedType(ownerTypeDesc, typeVarName, typeArg);
         }
         else if (typeArg instanceof GenericArrayType) {
            addMappingForArrayType(ownerTypeDesc, typeVarName, typeArg);
         }
         else {
            addMappingForFirstTypeBound(ownerTypeDesc, typeParam);
         }
      }

      Type outerType = genericType.getOwnerType();

      if (outerType instanceof ParameterizedType) {
         ParameterizedType parameterizedOuterType = (ParameterizedType) outerType;
         Class rawOuterType = (Class) parameterizedOuterType.getRawType();
         addMappingsFromTypeParametersToTypeArguments(rawOuterType, parameterizedOuterType);
      }
   }

   private void addMappingForClassType(@Nonnull String ownerTypeDesc, @Nonnull String typeName, @Nonnull Type typeArg)
   {
      String mappedTypeArgName = null;

      if (withSignatures) {
         Class classArg = (Class) typeArg;
         String ownerClassDesc = getOwnerClassDesc(classArg);
         mappedTypeArgName = classArg.isArray() ? ownerClassDesc : 'L' + ownerClassDesc;
      }

      addTypeMapping(ownerTypeDesc, typeName, typeArg, mappedTypeArgName);
   }

   private void addMappingForTypeVariable(
      @Nonnull String ownerTypeDesc, @Nonnull String typeName, @Nonnull Type typeArg)
   {
      @Nullable String mappedTypeArgName = null;

      if (withSignatures) {
         TypeVariable typeVar = (TypeVariable) typeArg;
         String ownerClassDesc = getOwnerClassDesc(typeVar);
         String intermediateTypeArg = ownerClassDesc + ":T" + typeVar.getName();
         mappedTypeArgName = typeParametersToTypeArgumentNames.get(intermediateTypeArg);
      }

      addTypeMapping(ownerTypeDesc, typeName, typeArg, mappedTypeArgName);
   }

   private void addMappingForParameterizedType(
      @Nonnull String ownerTypeDesc, @Nonnull String typeName, @Nonnull Type typeArg)
   {
      String mappedTypeArgName = getMappedTypeArgName(typeArg);
      addTypeMapping(ownerTypeDesc, typeName, typeArg, mappedTypeArgName);
   }

   @Nullable
   private String getMappedTypeArgName(@Nonnull Type typeArg)
   {
      if (withSignatures) {
         Class classType = getClassType(typeArg);
         return 'L' + getOwnerClassDesc(classType);
      }

      return null;
   }

   private void addMappingForArrayType(@Nonnull String ownerTypeDesc, @Nonnull String typeName, @Nonnull Type typeArg)
   {
      String mappedTypeArgName = null;

      if (withSignatures) {
         mappedTypeArgName = getMappedTypeArgName((GenericArrayType) typeArg);
      }

      addTypeMapping(ownerTypeDesc, typeName, typeArg, mappedTypeArgName);
   }

   private void addMappingForFirstTypeBound(@Nonnull String ownerTypeDesc, @Nonnull TypeVariable typeParam)
   {
      Type typeArg = typeParam.getBounds()[0];
      String mappedTypeArgName = getMappedTypeArgName(typeArg);
      addTypeMapping(ownerTypeDesc, typeParam.getName(), typeArg, mappedTypeArgName);
   }

   @Nonnull
   private static String getOwnerClassDesc(@Nonnull Class rawType) { return rawType.getName().replace('.', '/'); }

   @Nonnull
   private Class getClassType(@Nonnull Type type)
   {
      if (type instanceof ParameterizedType) {
         ParameterizedType parameterizedType = (ParameterizedType) type;
         return (Class) parameterizedType.getRawType();
      }

      if (type instanceof TypeVariable) {
         TypeVariable typeVar = (TypeVariable) type;
         String typeVarKey = getTypeVariableKey(typeVar);
         @Nullable Type typeArg = typeParametersToTypeArguments.get(typeVarKey);

         if (typeArg == null) {
            throw new IllegalArgumentException("Unable to resolve type variable \"" + typeVar.getName() + '"');
         }

         //noinspection TailRecursion
         return getClassType(typeArg);
      }

      return (Class) type;
   }

   @Nonnull
   private String getMappedTypeArgName(@Nonnull GenericArrayType arrayType)
   {
      StringBuilder argName = new StringBuilder(20);
      argName.append('[');

      while (true) {
         Type componentType = arrayType.getGenericComponentType();

         if (componentType instanceof GenericArrayType) {
            argName.append('[');
            arrayType = (GenericArrayType) componentType;
         }
         else {
            Class classType = getClassType(componentType);
            argName.append('L').append(getOwnerClassDesc(classType));
            return argName.toString();
         }
      }
   }

   private void addTypeMapping(
      @Nonnull String ownerTypeDesc, @Nonnull String typeVarName,
      @Nonnull Type mappedTypeArg, @Nullable String mappedTypeArgName)
   {
      typeParametersToTypeArguments.put(ownerTypeDesc + ':' + typeVarName, mappedTypeArg);

      if (mappedTypeArgName != null) {
         addTypeMapping(ownerTypeDesc, typeVarName, mappedTypeArgName);
      }
   }

   private void addTypeMapping(
      @Nonnull String ownerTypeDesc, @Nonnull String typeVarName, @Nonnull String mappedTypeArgName)
   {
      String typeMappingKey = ownerTypeDesc + ":T" + typeVarName;
      typeParametersToTypeArgumentNames.put(typeMappingKey, mappedTypeArgName);
   }

   public final class GenericSignature
   {
      private final List parameters;
      private final String parameterTypeDescs;
      private final int lengthOfParameterTypeDescs;
      private int currentPos;

      GenericSignature(@Nonnull String signature)
      {
         int p = signature.indexOf('(');
         int q = signature.lastIndexOf(')');
         parameterTypeDescs = signature.substring(p + 1, q);
         lengthOfParameterTypeDescs = parameterTypeDescs.length();
         parameters = new ArrayList();
         addTypeDescsToList();
      }

      private void addTypeDescsToList()
      {
         while (currentPos < lengthOfParameterTypeDescs) {
            addNextParameter();
         }
      }

      private void addNextParameter()
      {
         int startPos = currentPos;
         int endPos;
         char c = parameterTypeDescs.charAt(startPos);

         if (c == 'T') {
            endPos = parameterTypeDescs.indexOf(';', startPos);
            currentPos = endPos;
         }
         else if (c == 'L') {
            endPos = advanceToEndOfTypeDesc();
         }
         else if (c == '[') {
            char elemTypeStart = firstCharacterOfArrayElementType();

            if (elemTypeStart == 'T') {
               endPos = parameterTypeDescs.indexOf(';', startPos);
               currentPos = endPos;
            }
            else if (elemTypeStart == 'L') {
               endPos = advanceToEndOfTypeDesc();
            }
            else {
               endPos = currentPos + 1;
            }
         }
         else {
            endPos = currentPos + 1;
         }

         currentPos++;
         String parameter = parameterTypeDescs.substring(startPos, endPos);
         parameters.add(parameter);
      }

      private int advanceToEndOfTypeDesc()
      {
         char c = '\0';

         do {
            currentPos++;
            if (currentPos == lengthOfParameterTypeDescs) break;
            c = parameterTypeDescs.charAt(currentPos);
         } while (c != ';' && c != '<');

         int endPos = currentPos;

         if (c == '<') {
            advancePastTypeArguments();
            currentPos++;
         }

         return endPos;
      }

      private char firstCharacterOfArrayElementType()
      {
         char c;

         do {
            currentPos++;
            c = parameterTypeDescs.charAt(currentPos);
         } while (c == '[');

         return c;
      }

      private void advancePastTypeArguments()
      {
         int angleBracketDepth = 1;

         do {
            currentPos++;
            char c = parameterTypeDescs.charAt(currentPos);
            if (c == '>') angleBracketDepth--; else if (c == '<') angleBracketDepth++;
         } while (angleBracketDepth > 0);
      }

      public boolean satisfiesGenericSignature(@Nonnull String otherSignature)
      {
         GenericSignature other = new GenericSignature(otherSignature);
         return areMatchingSignatures(other);
      }

      private boolean areMatchingSignatures(@Nonnull GenericSignature other)
      {
         int n = parameters.size();

         if (n != other.parameters.size()) {
            return false;
         }

         for (int i = 0; i < n; i++) {
            String p1 = other.parameters.get(i);
            String p2 = parameters.get(i);

            if (!areParametersOfSameType(p1, p2)) {
               return false;
            }
         }

         return true;
      }

      @SuppressWarnings("MethodWithMultipleLoops")
      private boolean areParametersOfSameType(@Nonnull String param1, @Nonnull String param2)
      {
         if (param1.equals(param2)) return true;

         int i = -1;
         char c;
         do { i++; c = param1.charAt(i); } while (c == '[');
         if (c != 'T') return false;

         String typeVarName1 = param1.substring(i);
         String typeVarName2 = param2.substring(i);
         String typeArg1 = null;

         for (Entry typeParamAndArgName : typeParametersToTypeArgumentNames.entrySet()) {
            String typeMappingKey = typeParamAndArgName.getKey();
            String typeVarName = typeMappingKey.substring(typeMappingKey.indexOf(':') + 1);

            if (typeVarName.equals(typeVarName1)) {
               typeArg1 = typeParamAndArgName.getValue();
               break;
            }
         }

         return typeVarName2.equals(typeArg1);
      }

      public boolean satisfiesSignature(@Nonnull String otherSignature)
      {
         GenericSignature other = new GenericSignature(otherSignature);
         return other.areMatchingSignatures(this);
      }
   }

   @Nonnull
   public GenericSignature parseSignature(@Nonnull String genericSignature)
   {
      return new GenericSignature(genericSignature);
   }

   @Nonnull
   public String resolveSignature(@Nonnull String ownerTypeDesc, @Nonnull String genericSignature)
   {
      addTypeArgumentsIfAvailable(ownerTypeDesc, genericSignature);

      int p = genericSignature.lastIndexOf(')') + 1;
      int q = genericSignature.length();
      String returnType = genericSignature.substring(p, q);
      String resolvedReturnType = replaceTypeParametersWithActualTypes(ownerTypeDesc, returnType);

      StringBuilder finalSignature = new StringBuilder(genericSignature);
      finalSignature.replace(p, q, resolvedReturnType);
      return finalSignature.toString();
   }

   private void addTypeArgumentsIfAvailable(@Nonnull String ownerTypeDesc, @Nonnull String signature)
   {
      int firstParen = signature.indexOf('(');
      if (firstParen == 0) return;

      int p = 1;
      boolean lastMappingFound = false;

      while (!lastMappingFound) {
         int q = signature.indexOf(':', p);
         String typeVar = signature.substring(p, q);

         q++;

         if (signature.charAt(q) == ':') {
            q++; // an unbounded type argument uses ":" as separator, while a bounded one uses "::"
         }

         int r = signature.indexOf(':', q);

         if (r < 0) {
            r = firstParen - 2;
            lastMappingFound = true;
         }
         else {
            r = signature.lastIndexOf(';', r);
            p = r + 1;
         }

         String typeArg = signature.substring(q, r);
         addTypeMapping(ownerTypeDesc, typeVar, typeArg);
      }
   }

   @Nonnull
   private String replaceTypeParametersWithActualTypes(@Nonnull String ownerTypeDesc, @Nonnull String typeDesc)
   {
      if (typeDesc.charAt(0) == 'T' && !typeParametersToTypeArgumentNames.isEmpty()) {
         return replaceTypeParameters(ownerTypeDesc, typeDesc);
      }

      int p = typeDesc.indexOf('<');

      if (p < 0) {
         return typeDesc;
      }

      String resolvedTypeDesc = typeDesc;

      for (Entry paramAndArg : typeParametersToTypeArgumentNames.entrySet()) {
         String typeMappingKey = paramAndArg.getKey();
         String typeParam = typeMappingKey.substring(typeMappingKey.indexOf(':') + 1) + ';';
         String typeArg = paramAndArg.getValue() + ';';
         resolvedTypeDesc = resolvedTypeDesc.replace(typeParam, typeArg);
      }

      return resolvedTypeDesc;
   }

   @Nonnull
   private String replaceTypeParameters(@Nonnull String ownerTypeDesc, @Nonnull String typeDesc)
   {
      String typeParameter = typeDesc.substring(0, typeDesc.length() - 1);

      while (true) {
         @Nullable String typeArg = typeParametersToTypeArgumentNames.get(ownerTypeDesc + ':' + typeParameter);

         if (typeArg == null) {
            return typeDesc;
         }

         if (typeArg.charAt(0) != 'T') {
            return typeArg + ';';
         }

         typeParameter = typeArg;
      }
   }

   @Nonnull
   public Type resolveTypeVariable(@Nonnull TypeVariable typeVariable)
   {
      String typeVarKey = getTypeVariableKey(typeVariable);
      @Nullable Type typeArgument = typeParametersToTypeArguments.get(typeVarKey);

      if (typeArgument == null) {
         typeArgument = typeVariable.getBounds()[0];
      }

      if (typeArgument instanceof TypeVariable) {
         typeArgument = resolveTypeVariable((TypeVariable) typeArgument);
      }

      return typeArgument;
   }

   @Nonnull
   private String getTypeVariableKey(@Nonnull TypeVariable typeVariable)
   {
      String ownerClassDesc = getOwnerClassDesc(typeVariable);
      return ownerClassDesc + ':' + typeVariable.getName();
   }

   @Nonnull
   private String getOwnerClassDesc(@Nonnull TypeVariable typeVariable)
   {
      GenericDeclaration owner = typeVariable.getGenericDeclaration();
      Class ownerClass = owner instanceof Member ? ((Member) owner).getDeclaringClass() : (Class) owner;
      return getOwnerClassDesc(ownerClass);
   }

   @Nonnull
   public String resolveReturnType(@Nonnull String genericSignature)
   {
      int p = genericSignature.lastIndexOf(')') + 1;

      if (typeParametersToTypeArgumentNames.isEmpty() && genericSignature.charAt(0) != '<') {
         return genericSignature.substring(p);
      }

      int q = genericSignature.length();
      String returnType = genericSignature.substring(p, q);
      String resolvedReturnType = resolveReturnType(ownerType, returnType);
      String resolvedSignature;

      if (resolvedReturnType == null) {
         resolvedSignature = returnType;
      }
      else if (resolvedReturnType.charAt(0) == '[') {
         return resolvedReturnType;
      }
      else {
         StringBuilder finalSignature = new StringBuilder(genericSignature);
         finalSignature.replace(p, q, resolvedReturnType);
         resolvedSignature = finalSignature.toString();
      }

      p = resolvedSignature.indexOf(')');
      return resolvedSignature.substring(p + 1);
   }

   @Nullable
   private String resolveReturnType(@Nonnull Class ownerType, @Nonnull String genericReturnType)
   {
      do {
         String ownerTypeDesc = getOwnerClassDesc(ownerType);
         String resolvedReturnType = replaceTypeParametersWithActualTypes(ownerTypeDesc, genericReturnType);

         if (!resolvedReturnType.equals(genericReturnType)) {
            return resolvedReturnType;
         }

         resolvedReturnType = resolveReturnTypeForAbstractMethod(ownerType, genericReturnType);

         if (resolvedReturnType != null) {
            return resolvedReturnType;
         }

         ownerType = ownerType.getSuperclass();
      }
      while (ownerType != null && ownerType != Object.class);

      return null;
   }

   @Nullable
   private String resolveReturnTypeForAbstractMethod(@Nonnull Class ownerType, @Nonnull String genericReturnType)
   {
      String resolvedReturnType = null;

      for (Class superInterface: ownerType.getInterfaces()) {
         resolvedReturnType = resolveReturnType(superInterface, genericReturnType);

         if (resolvedReturnType != null) {
            return resolvedReturnType;
         }
      }

      Class outerClass = ownerType.getEnclosingClass();

      if (outerClass != null) {
         resolvedReturnType = resolveReturnType(outerClass, genericReturnType);
      }

      return resolvedReturnType;
   }

   public boolean areMatchingTypes(@Nonnull Type declarationType, @Nonnull Type realizationType)
   {
      if (declarationType.equals(realizationType)) {
         return true;
      }

      if (declarationType instanceof Class) {
         if (realizationType instanceof Class) {
            return ((Class) declarationType).isAssignableFrom((Class) realizationType);
         }
      }
      else if (declarationType instanceof TypeVariable) {
         if (realizationType instanceof TypeVariable) {
            return false;
         }

         if (areMatchingTypes((TypeVariable) declarationType, realizationType)) {
            return true;
         }
      }
      else if (declarationType instanceof ParameterizedType) {
         ParameterizedType parameterizedDeclarationType = (ParameterizedType) declarationType;
         ParameterizedType parameterizedRealizationType = getParameterizedType(realizationType);

         if (parameterizedRealizationType != null) {
            return areMatchingTypes(parameterizedDeclarationType, parameterizedRealizationType);
         }
      }

      return false;
   }

   @Nullable
   private ParameterizedType getParameterizedType(@Nonnull Type realizationType)
   {
      if (realizationType instanceof ParameterizedType) {
         return (ParameterizedType) realizationType;
      }

      if (realizationType instanceof Class) {
         return findRealizationSupertype((Class) realizationType);
      }

      return null;
   }

   @Nullable
   private ParameterizedType findRealizationSupertype(@Nonnull Class realizationType)
   {
      Type realizationSuperclass = realizationType.getGenericSuperclass();
      ParameterizedType parameterizedRealizationType = null;

      // TODO: should recurse up to java.lang.Object, and to multiple super-interfaces?
      if (realizationSuperclass instanceof ParameterizedType) {
         parameterizedRealizationType = (ParameterizedType) realizationSuperclass;
      }
      else {
         for (Type realizationSupertype : realizationType.getGenericInterfaces()) {
            if (realizationSupertype instanceof ParameterizedType) {
               parameterizedRealizationType = (ParameterizedType) realizationSupertype;
               break;
            }
         }
      }

      return parameterizedRealizationType;
   }

   private boolean areMatchingTypes(@Nonnull TypeVariable declarationType, @Nonnull Type realizationType)
   {
      String typeVarKey = getTypeVariableKey(declarationType);
      @Nullable Type resolvedType = typeParametersToTypeArguments.get(typeVarKey);

      return
         resolvedType != null &&
         (resolvedType.equals(realizationType) || typeSatisfiesResolvedTypeVariable(resolvedType, realizationType));
   }

   private boolean areMatchingTypes(
      @Nonnull ParameterizedType declarationType, @Nonnull ParameterizedType realizationType)
   {
      return
         declarationType.getRawType().equals(realizationType.getRawType()) &&
         haveMatchingActualTypeArguments(declarationType, realizationType);
   }

   private boolean haveMatchingActualTypeArguments(
      @Nonnull ParameterizedType declarationType, @Nonnull ParameterizedType realizationType)
   {
      Type[] declaredTypeArguments = declarationType.getActualTypeArguments();
      Type[] concreteTypeArguments = realizationType.getActualTypeArguments();

      for (int i = 0, n = declaredTypeArguments.length; i < n; i++) {
         Type declaredTypeArg = declaredTypeArguments[i];
         Type concreteTypeArg = concreteTypeArguments[i];

         if (declaredTypeArg instanceof TypeVariable) {
            if (areMatchingTypeArguments((TypeVariable) declaredTypeArg, concreteTypeArg)) {
               continue;
            }
         }
         else if (areMatchingTypes(declaredTypeArg, concreteTypeArg)) {
            continue;
         }

         return false;
      }

      return true;
   }

   private boolean areMatchingTypeArguments(@Nonnull TypeVariable declaredType, @Nonnull Type concreteType)
   {
      String typeVarKey = getTypeVariableKey(declaredType);
      @Nullable Type resolvedType = typeParametersToTypeArguments.get(typeVarKey);

      if (resolvedType != null) {
         if (resolvedType.equals(concreteType)) {
            return true;
         }

         if (
            concreteType instanceof Class &&
            typeSatisfiesResolvedTypeVariable(resolvedType, (Class) concreteType)
         ) {
            return true;
         }

         if (
            concreteType instanceof WildcardType &&
            typeSatisfiesUpperBounds(resolvedType, ((WildcardType) concreteType).getUpperBounds())
         ) {
            return true;
         }
      }
      else if (typeSatisfiesUpperBounds(concreteType, declaredType.getBounds())) {
         return true;
      }

      return false;
   }

   private boolean typeSatisfiesResolvedTypeVariable(@Nonnull Type resolvedType, @Nonnull Type realizationType)
   {
      Class realizationClass = getClassType(realizationType);
      return typeSatisfiesResolvedTypeVariable(resolvedType, realizationClass);
   }

   private boolean typeSatisfiesResolvedTypeVariable(@Nonnull Type resolvedType, @Nonnull Class realizationType)
   {
      Class resolvedClass = getClassType(resolvedType);
      return resolvedClass.isAssignableFrom(realizationType);
   }

   private boolean typeSatisfiesUpperBounds(@Nonnull Type type, @Nonnull Type[] upperBounds)
   {
      Class classType = getClassType(type);

      for (Type upperBound : upperBounds) {
         Class classBound = getClassType(upperBound);

         if (!classBound.isAssignableFrom(classType)) {
            return false;
         }
      }

      return true;
   }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy