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<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<K,V> is a generic class, and 105 * a corresponding ParameterizedType might look like 106 * Map<K=String,V=Integer>. Given such a ParameterizedType, this method 107 * will replace K with String, or List<K> with List<String;, or 108 * List<? super K> with List<? 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 <T>, the erasure 116 * is Object. For a type parameter declared as <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<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<String,List<Integer>> {} 145 * public interface RawStringToIntListMap extends StringToIntListMap {} 146 * </pre> 147 * 148 * <p>...the V inherited from Map will show up as List<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™ 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