TypeParameterResolver.java

  1. /*
  2.  *    Copyright 2009-2021 the original author or authors.
  3.  *
  4.  *    Licensed under the Apache License, Version 2.0 (the "License");
  5.  *    you may not use this file except in compliance with the License.
  6.  *    You may obtain a copy of the License at
  7.  *
  8.  *       http://www.apache.org/licenses/LICENSE-2.0
  9.  *
  10.  *    Unless required by applicable law or agreed to in writing, software
  11.  *    distributed under the License is distributed on an "AS IS" BASIS,
  12.  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13.  *    See the License for the specific language governing permissions and
  14.  *    limitations under the License.
  15.  */
  16. package org.apache.ibatis.reflection;

  17. import java.lang.reflect.Array;
  18. import java.lang.reflect.Field;
  19. import java.lang.reflect.GenericArrayType;
  20. import java.lang.reflect.Method;
  21. import java.lang.reflect.ParameterizedType;
  22. import java.lang.reflect.Type;
  23. import java.lang.reflect.TypeVariable;
  24. import java.lang.reflect.WildcardType;
  25. import java.util.Arrays;

  26. /**
  27.  * @author Iwao AVE!
  28.  */
  29. public class TypeParameterResolver {

  30.   /**
  31.    * Resolve field type.
  32.    *
  33.    * @param field
  34.    *          the field
  35.    * @param srcType
  36.    *          the src type
  37.    * @return The field type as {@link Type}. If it has type parameters in the declaration,<br>
  38.    *         they will be resolved to the actual runtime {@link Type}s.
  39.    */
  40.   public static Type resolveFieldType(Field field, Type srcType) {
  41.     Type fieldType = field.getGenericType();
  42.     Class<?> declaringClass = field.getDeclaringClass();
  43.     return resolveType(fieldType, srcType, declaringClass);
  44.   }

  45.   /**
  46.    * Resolve return type.
  47.    *
  48.    * @param method
  49.    *          the method
  50.    * @param srcType
  51.    *          the src type
  52.    * @return The return type of the method as {@link Type}. If it has type parameters in the declaration,<br>
  53.    *         they will be resolved to the actual runtime {@link Type}s.
  54.    */
  55.   public static Type resolveReturnType(Method method, Type srcType) {
  56.     Type returnType = method.getGenericReturnType();
  57.     Class<?> declaringClass = method.getDeclaringClass();
  58.     return resolveType(returnType, srcType, declaringClass);
  59.   }

  60.   /**
  61.    * Resolve param types.
  62.    *
  63.    * @param method
  64.    *          the method
  65.    * @param srcType
  66.    *          the src type
  67.    * @return The parameter types of the method as an array of {@link Type}s. If they have type parameters in the
  68.    *         declaration,<br>
  69.    *         they will be resolved to the actual runtime {@link Type}s.
  70.    */
  71.   public static Type[] resolveParamTypes(Method method, Type srcType) {
  72.     Type[] paramTypes = method.getGenericParameterTypes();
  73.     Class<?> declaringClass = method.getDeclaringClass();
  74.     Type[] result = new Type[paramTypes.length];
  75.     for (int i = 0; i < paramTypes.length; i++) {
  76.       result[i] = resolveType(paramTypes[i], srcType, declaringClass);
  77.     }
  78.     return result;
  79.   }

  80.   private static Type resolveType(Type type, Type srcType, Class<?> declaringClass) {
  81.     if (type instanceof TypeVariable) {
  82.       return resolveTypeVar((TypeVariable<?>) type, srcType, declaringClass);
  83.     } else if (type instanceof ParameterizedType) {
  84.       return resolveParameterizedType((ParameterizedType) type, srcType, declaringClass);
  85.     } else if (type instanceof GenericArrayType) {
  86.       return resolveGenericArrayType((GenericArrayType) type, srcType, declaringClass);
  87.     } else {
  88.       return type;
  89.     }
  90.   }

  91.   private static Type resolveGenericArrayType(GenericArrayType genericArrayType, Type srcType, Class<?> declaringClass) {
  92.     Type componentType = genericArrayType.getGenericComponentType();
  93.     Type resolvedComponentType = null;
  94.     if (componentType instanceof TypeVariable) {
  95.       resolvedComponentType = resolveTypeVar((TypeVariable<?>) componentType, srcType, declaringClass);
  96.     } else if (componentType instanceof GenericArrayType) {
  97.       resolvedComponentType = resolveGenericArrayType((GenericArrayType) componentType, srcType, declaringClass);
  98.     } else if (componentType instanceof ParameterizedType) {
  99.       resolvedComponentType = resolveParameterizedType((ParameterizedType) componentType, srcType, declaringClass);
  100.     }
  101.     if (resolvedComponentType instanceof Class) {
  102.       return Array.newInstance((Class<?>) resolvedComponentType, 0).getClass();
  103.     } else {
  104.       return new GenericArrayTypeImpl(resolvedComponentType);
  105.     }
  106.   }

  107.   private static ParameterizedType resolveParameterizedType(ParameterizedType parameterizedType, Type srcType, Class<?> declaringClass) {
  108.     Class<?> rawType = (Class<?>) parameterizedType.getRawType();
  109.     Type[] typeArgs = parameterizedType.getActualTypeArguments();
  110.     Type[] args = new Type[typeArgs.length];
  111.     for (int i = 0; i < typeArgs.length; i++) {
  112.       if (typeArgs[i] instanceof TypeVariable) {
  113.         args[i] = resolveTypeVar((TypeVariable<?>) typeArgs[i], srcType, declaringClass);
  114.       } else if (typeArgs[i] instanceof ParameterizedType) {
  115.         args[i] = resolveParameterizedType((ParameterizedType) typeArgs[i], srcType, declaringClass);
  116.       } else if (typeArgs[i] instanceof WildcardType) {
  117.         args[i] = resolveWildcardType((WildcardType) typeArgs[i], srcType, declaringClass);
  118.       } else {
  119.         args[i] = typeArgs[i];
  120.       }
  121.     }
  122.     return new ParameterizedTypeImpl(rawType, null, args);
  123.   }

  124.   private static Type resolveWildcardType(WildcardType wildcardType, Type srcType, Class<?> declaringClass) {
  125.     Type[] lowerBounds = resolveWildcardTypeBounds(wildcardType.getLowerBounds(), srcType, declaringClass);
  126.     Type[] upperBounds = resolveWildcardTypeBounds(wildcardType.getUpperBounds(), srcType, declaringClass);
  127.     return new WildcardTypeImpl(lowerBounds, upperBounds);
  128.   }

  129.   private static Type[] resolveWildcardTypeBounds(Type[] bounds, Type srcType, Class<?> declaringClass) {
  130.     Type[] result = new Type[bounds.length];
  131.     for (int i = 0; i < bounds.length; i++) {
  132.       if (bounds[i] instanceof TypeVariable) {
  133.         result[i] = resolveTypeVar((TypeVariable<?>) bounds[i], srcType, declaringClass);
  134.       } else if (bounds[i] instanceof ParameterizedType) {
  135.         result[i] = resolveParameterizedType((ParameterizedType) bounds[i], srcType, declaringClass);
  136.       } else if (bounds[i] instanceof WildcardType) {
  137.         result[i] = resolveWildcardType((WildcardType) bounds[i], srcType, declaringClass);
  138.       } else {
  139.         result[i] = bounds[i];
  140.       }
  141.     }
  142.     return result;
  143.   }

  144.   private static Type resolveTypeVar(TypeVariable<?> typeVar, Type srcType, Class<?> declaringClass) {
  145.     Type result;
  146.     Class<?> clazz;
  147.     if (srcType instanceof Class) {
  148.       clazz = (Class<?>) srcType;
  149.     } else if (srcType instanceof ParameterizedType) {
  150.       ParameterizedType parameterizedType = (ParameterizedType) srcType;
  151.       clazz = (Class<?>) parameterizedType.getRawType();
  152.     } else {
  153.       throw new IllegalArgumentException("The 2nd arg must be Class or ParameterizedType, but was: " + srcType.getClass());
  154.     }

  155.     if (clazz == declaringClass) {
  156.       Type[] bounds = typeVar.getBounds();
  157.       if (bounds.length > 0) {
  158.         return bounds[0];
  159.       }
  160.       return Object.class;
  161.     }

  162.     Type superclass = clazz.getGenericSuperclass();
  163.     result = scanSuperTypes(typeVar, srcType, declaringClass, clazz, superclass);
  164.     if (result != null) {
  165.       return result;
  166.     }

  167.     Type[] superInterfaces = clazz.getGenericInterfaces();
  168.     for (Type superInterface : superInterfaces) {
  169.       result = scanSuperTypes(typeVar, srcType, declaringClass, clazz, superInterface);
  170.       if (result != null) {
  171.         return result;
  172.       }
  173.     }
  174.     return Object.class;
  175.   }

  176.   private static Type scanSuperTypes(TypeVariable<?> typeVar, Type srcType, Class<?> declaringClass, Class<?> clazz, Type superclass) {
  177.     if (superclass instanceof ParameterizedType) {
  178.       ParameterizedType parentAsType = (ParameterizedType) superclass;
  179.       Class<?> parentAsClass = (Class<?>) parentAsType.getRawType();
  180.       TypeVariable<?>[] parentTypeVars = parentAsClass.getTypeParameters();
  181.       if (srcType instanceof ParameterizedType) {
  182.         parentAsType = translateParentTypeVars((ParameterizedType) srcType, clazz, parentAsType);
  183.       }
  184.       if (declaringClass == parentAsClass) {
  185.         for (int i = 0; i < parentTypeVars.length; i++) {
  186.           if (typeVar.equals(parentTypeVars[i])) {
  187.             return parentAsType.getActualTypeArguments()[i];
  188.           }
  189.         }
  190.       }
  191.       if (declaringClass.isAssignableFrom(parentAsClass)) {
  192.         return resolveTypeVar(typeVar, parentAsType, declaringClass);
  193.       }
  194.     } else if (superclass instanceof Class && declaringClass.isAssignableFrom((Class<?>) superclass)) {
  195.       return resolveTypeVar(typeVar, superclass, declaringClass);
  196.     }
  197.     return null;
  198.   }

  199.   private static ParameterizedType translateParentTypeVars(ParameterizedType srcType, Class<?> srcClass, ParameterizedType parentType) {
  200.     Type[] parentTypeArgs = parentType.getActualTypeArguments();
  201.     Type[] srcTypeArgs = srcType.getActualTypeArguments();
  202.     TypeVariable<?>[] srcTypeVars = srcClass.getTypeParameters();
  203.     Type[] newParentArgs = new Type[parentTypeArgs.length];
  204.     boolean noChange = true;
  205.     for (int i = 0; i < parentTypeArgs.length; i++) {
  206.       if (parentTypeArgs[i] instanceof TypeVariable) {
  207.         for (int j = 0; j < srcTypeVars.length; j++) {
  208.           if (srcTypeVars[j].equals(parentTypeArgs[i])) {
  209.             noChange = false;
  210.             newParentArgs[i] = srcTypeArgs[j];
  211.           }
  212.         }
  213.       } else {
  214.         newParentArgs[i] = parentTypeArgs[i];
  215.       }
  216.     }
  217.     return noChange ? parentType : new ParameterizedTypeImpl((Class<?>)parentType.getRawType(), null, newParentArgs);
  218.   }

  219.   private TypeParameterResolver() {
  220.     super();
  221.   }

  222.   static class ParameterizedTypeImpl implements ParameterizedType {
  223.     private Class<?> rawType;

  224.     private Type ownerType;

  225.     private Type[] actualTypeArguments;

  226.     public ParameterizedTypeImpl(Class<?> rawType, Type ownerType, Type[] actualTypeArguments) {
  227.       super();
  228.       this.rawType = rawType;
  229.       this.ownerType = ownerType;
  230.       this.actualTypeArguments = actualTypeArguments;
  231.     }

  232.     @Override
  233.     public Type[] getActualTypeArguments() {
  234.       return actualTypeArguments;
  235.     }

  236.     @Override
  237.     public Type getOwnerType() {
  238.       return ownerType;
  239.     }

  240.     @Override
  241.     public Type getRawType() {
  242.       return rawType;
  243.     }

  244.     @Override
  245.     public String toString() {
  246.       return "ParameterizedTypeImpl [rawType=" + rawType + ", ownerType=" + ownerType + ", actualTypeArguments=" + Arrays.toString(actualTypeArguments) + "]";
  247.     }
  248.   }

  249.   static class WildcardTypeImpl implements WildcardType {
  250.     private Type[] lowerBounds;

  251.     private Type[] upperBounds;

  252.     WildcardTypeImpl(Type[] lowerBounds, Type[] upperBounds) {
  253.       super();
  254.       this.lowerBounds = lowerBounds;
  255.       this.upperBounds = upperBounds;
  256.     }

  257.     @Override
  258.     public Type[] getLowerBounds() {
  259.       return lowerBounds;
  260.     }

  261.     @Override
  262.     public Type[] getUpperBounds() {
  263.       return upperBounds;
  264.     }
  265.   }

  266.   static class GenericArrayTypeImpl implements GenericArrayType {
  267.     private Type genericComponentType;

  268.     GenericArrayTypeImpl(Type genericComponentType) {
  269.       super();
  270.       this.genericComponentType = genericComponentType;
  271.     }

  272.     @Override
  273.     public Type getGenericComponentType() {
  274.       return genericComponentType;
  275.     }
  276.   }
  277. }