1 /*
2  * Copyright (c) 2003, 2018, 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      */
resolveInClass(Class<?> inClass, Type type)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      */
resolveInClass(Class<?> inClass, Type[] types)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      */
resolve(Type actual, Type formal)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      */
resolve(Type actual, Type[] formals)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      */
erase(Type type)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      */
erase(Type[] types)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      */
prepare(Map<Type, Type> map, Type type)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="https://bugs.java.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      */
fixGenericArray(Type type)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      */
getActualType(Class<?> inClass)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 }
379