1 /*
   2  * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package com.sun.beans;
  26 
  27 import java.lang.reflect.Array;
  28 import java.lang.reflect.GenericArrayType;
  29 import java.lang.reflect.ParameterizedType;
  30 import java.lang.reflect.Type;
  31 import java.lang.reflect.TypeVariable;
  32 import java.lang.reflect.WildcardType;
  33 import java.util.HashMap;
  34 import java.util.Map;
  35 
  36 import sun.reflect.generics.reflectiveObjects.GenericArrayTypeImpl;
  37 import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;
  38 
  39 /**
  40  * This is utility class to resolve types.
  41  *
  42  * @since 1.7
  43  *
  44  * @author Eamonn McManus
  45  * @author Sergey Malenkov
  46  */
  47 public final class TypeResolver {
  48 
  49     private static final WeakCache<Type, Map<Type, Type>> CACHE = new WeakCache<>();
  50 
  51     /**
  52      * Replaces the given {@code type} in an inherited method
  53      * with the actual type it has in the given {@code inClass}.
  54      *
  55      * <p>Although type parameters are not inherited by subclasses in the Java
  56      * language, they <em>are</em> effectively inherited when using reflection.
  57      * For example, if you declare an interface like this...</p>
  58      *
  59      * <pre>
  60      * public interface StringToIntMap extends Map&lt;String,Integer> {}
  61      * </pre>
  62      *
  63      * <p>...then StringToIntMap.class.getMethods() will show that it has methods
  64      * like put(K,V) even though StringToIntMap has no type parameters.  The K
  65      * and V variables are the ones declared by Map, so
  66      * {@link TypeVariable#getGenericDeclaration()} will return Map.class.</p>
  67      *
  68      * <p>The purpose of this method is to take a Type from a possibly-inherited
  69      * method and replace it with the correct Type for the inheriting class.
  70      * So given parameters of K and StringToIntMap.class in the above example,
  71      * this method will return String.</p>
  72      *
  73      * @param inClass  the base class used to resolve
  74      * @param type     the type to resolve
  75      * @return a resolved type
  76      *
  77      * @see #getActualType(Class)
  78      * @see #resolve(Type,Type)
  79      */
  80     public static Type resolveInClass(Class<?> inClass, Type type) {
  81         return resolve(getActualType(inClass), type);
  82     }
  83 
  84     /**
  85      * Replaces all {@code types} in the given array
  86      * with the actual types they have in the given {@code inClass}.
  87      *
  88      * @param inClass  the base class used to resolve
  89      * @param types    the array of types to resolve
  90      * @return an array of resolved types
  91      *
  92      * @see #getActualType(Class)
  93      * @see #resolve(Type,Type[])
  94      */
  95     public static Type[] resolveInClass(Class<?> inClass, Type[] types) {
  96         return resolve(getActualType(inClass), types);
  97     }
  98 
  99     /**
 100      * Replaces type variables of the given {@code formal} type
 101      * with the types they stand for in the given {@code actual} type.
 102      *
 103      * <p>A ParameterizedType is a class with type parameters, and the values
 104      * of those parameters.  For example, Map&lt;K,V> is a generic class, and
 105      * a corresponding ParameterizedType might look like
 106      * Map&lt;K=String,V=Integer>.  Given such a ParameterizedType, this method
 107      * will replace K with String, or List&lt;K> with List&ltString;, or
 108      * List&lt;? super K> with List&lt;? super String>.</p>
 109      *
 110      * <p>The {@code actual} argument to this method can also be a Class.
 111      * In this case, either it is equivalent to a ParameterizedType with
 112      * no parameters (for example, Integer.class), or it is equivalent to
 113      * a "raw" ParameterizedType (for example, Map.class).  In the latter
 114      * case, every type parameter declared or inherited by the class is replaced
 115      * by its "erasure".  For a type parameter declared as &lt;T>, the erasure
 116      * is Object.  For a type parameter declared as &lt;T extends Number>,
 117      * the erasure is Number.</p>
 118      *
 119      * <p>Although type parameters are not inherited by subclasses in the Java
 120      * language, they <em>are</em> effectively inherited when using reflection.
 121      * For example, if you declare an interface like this...</p>
 122      *
 123      * <pre>
 124      * public interface StringToIntMap extends Map&lt;String,Integer> {}
 125      * </pre>
 126      *
 127      * <p>...then StringToIntMap.class.getMethods() will show that it has methods
 128      * like put(K,V) even though StringToIntMap has no type parameters.  The K
 129      * and V variables are the ones declared by Map, so
 130      * {@link TypeVariable#getGenericDeclaration()} will return {@link Map Map.class}.</p>
 131      *
 132      * <p>For this reason, this method replaces inherited type parameters too.
 133      * Therefore if this method is called with {@code actual} being
 134      * StringToIntMap.class and {@code formal} being the K from Map,
 135      * it will return {@link String String.class}.</p>
 136      *
 137      * <p>In the case where {@code actual} is a "raw" ParameterizedType, the
 138      * inherited type parameters will also be replaced by their erasures.
 139      * The erasure of a Class is the Class itself, so a "raw" subinterface of
 140      * StringToIntMap will still show the K from Map as String.class.  But
 141      * in a case like this...
 142      *
 143      * <pre>
 144      * public interface StringToIntListMap extends Map&lt;String,List&lt;Integer>> {}
 145      * public interface RawStringToIntListMap extends StringToIntListMap {}
 146      * </pre>
 147      *
 148      * <p>...the V inherited from Map will show up as List&lt;Integer> in
 149      * StringToIntListMap, but as plain List in RawStringToIntListMap.</p>
 150      *
 151      * @param actual  the type that supplies bindings for type variables
 152      * @param formal  the type where occurrences of the variables
 153      *                in {@code actual} will be replaced by the corresponding bound values
 154      * @return a resolved type
 155      */
 156     public static Type resolve(Type actual, Type formal) {
 157         if (formal instanceof Class) {
 158             return formal;
 159         }
 160         if (formal instanceof GenericArrayType) {
 161             Type comp = ((GenericArrayType) formal).getGenericComponentType();
 162             comp = resolve(actual, comp);
 163             return (comp instanceof Class)
 164                     ? Array.newInstance((Class<?>) comp, 0).getClass()
 165                     : GenericArrayTypeImpl.make(comp);
 166         }
 167         if (formal instanceof ParameterizedType) {
 168             ParameterizedType fpt = (ParameterizedType) formal;
 169             Type[] actuals = resolve(actual, fpt.getActualTypeArguments());
 170             return ParameterizedTypeImpl.make(
 171                     (Class<?>) fpt.getRawType(), actuals, fpt.getOwnerType());
 172         }
 173         if (formal instanceof WildcardType) {
 174             WildcardType fwt = (WildcardType) formal;
 175             Type[] upper = resolve(actual, fwt.getUpperBounds());
 176             Type[] lower = resolve(actual, fwt.getLowerBounds());
 177             return new WildcardTypeImpl(upper, lower);
 178         }
 179         if (formal instanceof TypeVariable) {
 180             Map<Type, Type> map;
 181             synchronized (CACHE) {
 182                 map = CACHE.get(actual);
 183                 if (map == null) {
 184                     map = new HashMap<>();
 185                     prepare(map, actual);
 186                     CACHE.put(actual, map);
 187                 }
 188             }
 189             Type result = map.get(formal);
 190             if (result == null || result.equals(formal)) {
 191                 return formal;
 192             }
 193             result = fixGenericArray(result);
 194             // A variable can be bound to another variable that is itself bound
 195             // to something.  For example, given:
 196             // class Super<T> {...}
 197             // class Mid<X> extends Super<T> {...}
 198             // class Sub extends Mid<String>
 199             // the variable T is bound to X, which is in turn bound to String.
 200             // So if we have to resolve T, we need the tail recursion here.
 201             return resolve(actual, result);
 202         }
 203         throw new IllegalArgumentException("Bad Type kind: " + formal.getClass());
 204     }
 205 
 206     /**
 207      * Replaces type variables of all formal types in the given array
 208      * with the types they stand for in the given {@code actual} type.
 209      *
 210      * @param actual   the type that supplies bindings for type variables
 211      * @param formals  the array of types to resolve
 212      * @return an array of resolved types
 213      */
 214     public static Type[] resolve(Type actual, Type[] formals) {
 215         int length = formals.length;
 216         Type[] actuals = new Type[length];
 217         for (int i = 0; i < length; i++) {
 218             actuals[i] = resolve(actual, formals[i]);
 219         }
 220         return actuals;
 221     }
 222 
 223     /**
 224      * Converts the given {@code type} to the corresponding class.
 225      * This method implements the concept of type erasure,
 226      * that is described in section 4.6 of
 227      * <cite>The Java&trade; Language Specification</cite>.
 228      *
 229      * @param type  the array of types to convert
 230      * @return a corresponding class
 231      */
 232     public static Class<?> erase(Type type) {
 233         if (type instanceof Class) {
 234             return (Class<?>) type;
 235         }
 236         if (type instanceof ParameterizedType) {
 237             ParameterizedType pt = (ParameterizedType) type;
 238             return (Class<?>) pt.getRawType();
 239         }
 240         if (type instanceof TypeVariable) {
 241             TypeVariable<?> tv = (TypeVariable<?>)type;
 242             Type[] bounds = tv.getBounds();
 243             return (0 < bounds.length)
 244                     ? erase(bounds[0])
 245                     : Object.class;
 246         }
 247         if (type instanceof WildcardType) {
 248             WildcardType wt = (WildcardType)type;
 249             Type[] bounds = wt.getUpperBounds();
 250             return (0 < bounds.length)
 251                     ? erase(bounds[0])
 252                     : Object.class;
 253         }
 254         if (type instanceof GenericArrayType) {
 255             GenericArrayType gat = (GenericArrayType)type;
 256             return Array.newInstance(erase(gat.getGenericComponentType()), 0).getClass();
 257         }
 258         throw new IllegalArgumentException("Unknown Type kind: " + type.getClass());
 259     }
 260 
 261     /**
 262      * Converts all {@code types} in the given array
 263      * to the corresponding classes.
 264      *
 265      * @param types  the array of types to convert
 266      * @return an array of corresponding classes
 267      *
 268      * @see #erase(Type)
 269      */
 270     public static Class<?>[] erase(Type[] types) {
 271         int length = types.length;
 272         Class<?>[] classes = new Class<?>[length];
 273         for (int i = 0; i < length; i++) {
 274             classes[i] = TypeResolver.erase(types[i]);
 275         }
 276         return classes;
 277     }
 278 
 279     /**
 280      * Fills the map from type parameters
 281      * to types as seen by the given {@code type}.
 282      * The method is recursive because the {@code type}
 283      * inherits mappings from its parent classes and interfaces.
 284      * The {@code type} can be either a {@link Class Class}
 285      * or a {@link ParameterizedType ParameterizedType}.
 286      * If it is a {@link Class Class}, it is either equivalent
 287      * to a {@link ParameterizedType ParameterizedType} with no parameters,
 288      * or it represents the erasure of a {@link ParameterizedType ParameterizedType}.
 289      *
 290      * @param map   the mappings of all type variables
 291      * @param type  the next type in the hierarchy
 292      */
 293     private static void prepare(Map<Type, Type> map, Type type) {
 294         Class<?> raw = (Class<?>)((type instanceof Class<?>)
 295                 ? type
 296                 : ((ParameterizedType)type).getRawType());
 297 
 298         TypeVariable<?>[] formals = raw.getTypeParameters();
 299 
 300         Type[] actuals = (type instanceof Class<?>)
 301                 ? formals
 302                 : ((ParameterizedType)type).getActualTypeArguments();
 303 
 304         assert formals.length == actuals.length;
 305         for (int i = 0; i < formals.length; i++) {
 306             map.put(formals[i], actuals[i]);
 307         }
 308         Type gSuperclass = raw.getGenericSuperclass();
 309         if (gSuperclass != null) {
 310             prepare(map, gSuperclass);
 311         }
 312         for (Type gInterface : raw.getGenericInterfaces()) {
 313             prepare(map, gInterface);
 314         }
 315         // If type is the raw version of a parameterized class, we type-erase
 316         // all of its type variables, including inherited ones.
 317         if (type instanceof Class<?> && formals.length > 0) {
 318             for (Map.Entry<Type, Type> entry : map.entrySet()) {
 319                 entry.setValue(erase(entry.getValue()));
 320             }
 321         }
 322     }
 323 
 324     /**
 325      * Replaces a {@link GenericArrayType GenericArrayType}
 326      * with plain array class where it is possible.
 327      * Bug <a href="http://bugs.sun.com/view_bug.do?bug_id=5041784">5041784</a>
 328      * is that arrays of non-generic type sometimes show up
 329      * as {@link GenericArrayType GenericArrayType} when using reflection.
 330      * For example, a {@code String[]} might show up
 331      * as a {@link GenericArrayType GenericArrayType}
 332      * where {@link GenericArrayType#getGenericComponentType getGenericComponentType}
 333      * is {@code String.class}.  This violates the specification,
 334      * which says that {@link GenericArrayType GenericArrayType}
 335      * is used when the component type is a type variable or parameterized type.
 336      * We fit the specification here.
 337      *
 338      * @param type  the type to fix
 339      * @return a corresponding type for the generic array type,
 340      *         or the same type as {@code type}
 341      */
 342     private static Type fixGenericArray(Type type) {
 343         if (type instanceof GenericArrayType) {
 344             Type comp = ((GenericArrayType)type).getGenericComponentType();
 345             comp = fixGenericArray(comp);
 346             if (comp instanceof Class) {
 347                 return Array.newInstance((Class<?>)comp, 0).getClass();
 348             }
 349         }
 350         return type;
 351     }
 352 
 353     /**
 354      * Replaces a {@link Class Class} with type parameters
 355      * with a {@link ParameterizedType ParameterizedType}
 356      * where every parameter is bound to itself.
 357      * When calling {@link #resolveInClass} in the context of {@code inClass},
 358      * we can't just pass {@code inClass} as the {@code actual} parameter,
 359      * because if {@code inClass} has type parameters
 360      * that would be interpreted as accessing the raw type,
 361      * so we would get unwanted erasure.
 362      * This is why we bind each parameter to itself.
 363      * If {@code inClass} does have type parameters and has methods
 364      * where those parameters appear in the return type or argument types,
 365      * we will correctly leave those types alone.
 366      *
 367      * @param inClass  the base class used to resolve
 368      * @return a parameterized type for the class,
 369      *         or the same class as {@code inClass}
 370      */
 371     private static Type getActualType(Class<?> inClass) {
 372         Type[] params = inClass.getTypeParameters();
 373         return (params.length == 0)
 374                 ? inClass
 375                 : ParameterizedTypeImpl.make(
 376                         inClass, params, inClass.getEnclosingClass());
 377     }
 378 }