TypeParameterResolver.java

  1. /*
  2.  *    Copyright 2009-2024 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.  *       https://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.    *
  38.    * @return The field type as {@link Type}. If it has type parameters in the declaration,<br>
  39.    *         they will be resolved to the actual runtime {@link Type}s.
  40.    */
  41.   public static Type resolveFieldType(Field field, Type srcType) {
  42.     Type fieldType = field.getGenericType();
  43.     Class<?> declaringClass = field.getDeclaringClass();
  44.     return resolveType(fieldType, srcType, declaringClass);
  45.   }

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

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

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

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

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

  129.   private static Type resolveWildcardType(WildcardType wildcardType, Type srcType, Class<?> declaringClass) {
  130.     Type[] lowerBounds = resolveWildcardTypeBounds(wildcardType.getLowerBounds(), srcType, declaringClass);
  131.     Type[] upperBounds = resolveWildcardTypeBounds(wildcardType.getUpperBounds(), srcType, declaringClass);
  132.     return new WildcardTypeImpl(lowerBounds, upperBounds);
  133.   }

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

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

  161.     if (clazz == declaringClass) {
  162.       Type[] bounds = typeVar.getBounds();
  163.       if (bounds.length > 0) {
  164.         return bounds[0];
  165.       }
  166.       return Object.class;
  167.     }

  168.     Type superclass = clazz.getGenericSuperclass();
  169.     result = scanSuperTypes(typeVar, srcType, declaringClass, clazz, superclass);
  170.     if (result != null) {
  171.       return result;
  172.     }

  173.     Type[] superInterfaces = clazz.getGenericInterfaces();
  174.     for (Type superInterface : superInterfaces) {
  175.       result = scanSuperTypes(typeVar, srcType, declaringClass, clazz, superInterface);
  176.       if (result != null) {
  177.         return result;
  178.       }
  179.     }
  180.     return Object.class;
  181.   }

  182.   private static Type scanSuperTypes(TypeVariable<?> typeVar, Type srcType, Class<?> declaringClass, Class<?> clazz,
  183.       Type superclass) {
  184.     if (superclass instanceof ParameterizedType) {
  185.       ParameterizedType parentAsType = (ParameterizedType) superclass;
  186.       Class<?> parentAsClass = (Class<?>) parentAsType.getRawType();
  187.       TypeVariable<?>[] parentTypeVars = parentAsClass.getTypeParameters();
  188.       if (srcType instanceof ParameterizedType) {
  189.         parentAsType = translateParentTypeVars((ParameterizedType) srcType, clazz, parentAsType);
  190.       }
  191.       if (declaringClass == parentAsClass) {
  192.         for (int i = 0; i < parentTypeVars.length; i++) {
  193.           if (typeVar.equals(parentTypeVars[i])) {
  194.             Type actualType = parentAsType.getActualTypeArguments()[i];
  195.             return actualType instanceof TypeVariable<?> ? Object.class : actualType;
  196.           }
  197.         }
  198.       }
  199.       if (declaringClass.isAssignableFrom(parentAsClass)) {
  200.         return resolveTypeVar(typeVar, parentAsType, declaringClass);
  201.       }
  202.     } else if (superclass instanceof Class && declaringClass.isAssignableFrom((Class<?>) superclass)) {
  203.       return resolveTypeVar(typeVar, superclass, declaringClass);
  204.     }
  205.     return null;
  206.   }

  207.   private static ParameterizedType translateParentTypeVars(ParameterizedType srcType, Class<?> srcClass,
  208.       ParameterizedType parentType) {
  209.     Type[] parentTypeArgs = parentType.getActualTypeArguments();
  210.     Type[] srcTypeArgs = srcType.getActualTypeArguments();
  211.     TypeVariable<?>[] srcTypeVars = srcClass.getTypeParameters();
  212.     Type[] newParentArgs = new Type[parentTypeArgs.length];
  213.     boolean noChange = true;
  214.     for (int i = 0; i < parentTypeArgs.length; i++) {
  215.       if (parentTypeArgs[i] instanceof TypeVariable) {
  216.         for (int j = 0; j < srcTypeVars.length; j++) {
  217.           if (srcTypeVars[j].equals(parentTypeArgs[i])) {
  218.             noChange = false;
  219.             newParentArgs[i] = srcTypeArgs[j];
  220.           }
  221.         }
  222.       } else {
  223.         newParentArgs[i] = parentTypeArgs[i];
  224.       }
  225.     }
  226.     return noChange ? parentType : new ParameterizedTypeImpl((Class<?>) parentType.getRawType(), null, newParentArgs);
  227.   }

  228.   private TypeParameterResolver() {
  229.   }

  230.   static class ParameterizedTypeImpl implements ParameterizedType {
  231.     private final Class<?> rawType;

  232.     private final Type ownerType;

  233.     private final Type[] actualTypeArguments;

  234.     public ParameterizedTypeImpl(Class<?> rawType, Type ownerType, Type[] actualTypeArguments) {
  235.       this.rawType = rawType;
  236.       this.ownerType = ownerType;
  237.       this.actualTypeArguments = actualTypeArguments;
  238.     }

  239.     @Override
  240.     public Type[] getActualTypeArguments() {
  241.       return actualTypeArguments;
  242.     }

  243.     @Override
  244.     public Type getOwnerType() {
  245.       return ownerType;
  246.     }

  247.     @Override
  248.     public Type getRawType() {
  249.       return rawType;
  250.     }

  251.     @Override
  252.     public String toString() {
  253.       return "ParameterizedTypeImpl [rawType=" + rawType + ", ownerType=" + ownerType + ", actualTypeArguments="
  254.           + Arrays.toString(actualTypeArguments) + "]";
  255.     }
  256.   }

  257.   static class WildcardTypeImpl implements WildcardType {
  258.     private final Type[] lowerBounds;

  259.     private final Type[] upperBounds;

  260.     WildcardTypeImpl(Type[] lowerBounds, Type[] upperBounds) {
  261.       this.lowerBounds = lowerBounds;
  262.       this.upperBounds = upperBounds;
  263.     }

  264.     @Override
  265.     public Type[] getLowerBounds() {
  266.       return lowerBounds;
  267.     }

  268.     @Override
  269.     public Type[] getUpperBounds() {
  270.       return upperBounds;
  271.     }
  272.   }

  273.   static class GenericArrayTypeImpl implements GenericArrayType {
  274.     private final Type genericComponentType;

  275.     GenericArrayTypeImpl(Type genericComponentType) {
  276.       this.genericComponentType = genericComponentType;
  277.     }

  278.     @Override
  279.     public Type getGenericComponentType() {
  280.       return genericComponentType;
  281.     }
  282.   }
  283. }