1 /* 2 * Copyright (C) 2009 The Guava 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 17 package com.google.common.reflect; 18 19 import static com.google.common.base.Preconditions.checkArgument; 20 import static com.google.common.base.Preconditions.checkNotNull; 21 import static com.google.common.base.Preconditions.checkState; 22 23 import com.google.common.annotations.Beta; 24 import com.google.common.base.Joiner; 25 import com.google.common.base.Objects; 26 import com.google.common.collect.ImmutableMap; 27 import com.google.common.collect.Maps; 28 29 import java.lang.reflect.GenericArrayType; 30 import java.lang.reflect.ParameterizedType; 31 import java.lang.reflect.Type; 32 import java.lang.reflect.TypeVariable; 33 import java.lang.reflect.WildcardType; 34 import java.util.Arrays; 35 import java.util.Map; 36 import java.util.concurrent.atomic.AtomicInteger; 37 38 import javax.annotation.Nullable; 39 40 /** 41 * An object of this class encapsulates type mappings from type variables. Mappings are established 42 * with {@link #where} and types are resolved using {@link #resolveType}. 43 * 44 * <p>Note that usually type mappings are already implied by the static type hierarchy (for example, 45 * the {@code E} type variable declared by class {@code List} naturally maps to {@code String} in 46 * the context of {@code class MyStringList implements List<String>}. In such case, prefer to use 47 * {@link TypeToken#resolveType} since it's simpler and more type safe. This class should only be 48 * used when the type mapping isn't implied by the static type hierarchy, but provided through other 49 * means such as an annotation or external configuration file. 50 * 51 * @author Ben Yu 52 * @since 15.0 53 */ 54 @Beta 55 public final class TypeResolver { 56 57 private final TypeTable typeTable; 58 TypeResolver()59 public TypeResolver() { 60 this.typeTable = new TypeTable(); 61 } 62 TypeResolver(TypeTable typeTable)63 private TypeResolver(TypeTable typeTable) { 64 this.typeTable = typeTable; 65 } 66 accordingTo(Type type)67 static TypeResolver accordingTo(Type type) { 68 return new TypeResolver().where(TypeMappingIntrospector.getTypeMappings(type)); 69 } 70 71 /** 72 * Returns a new {@code TypeResolver} with type variables in {@code formal} mapping to types in 73 * {@code actual}. 74 * 75 * <p>For example, if {@code formal} is a {@code TypeVariable T}, and {@code actual} is {@code 76 * String.class}, then {@code new TypeResolver().where(formal, actual)} will {@linkplain 77 * #resolveType resolve} {@code ParameterizedType List<T>} to {@code List<String>}, and resolve 78 * {@code Map<T, Something>} to {@code Map<String, Something>} etc. Similarly, {@code formal} and 79 * {@code actual} can be {@code Map<K, V>} and {@code Map<String, Integer>} respectively, or they 80 * can be {@code E[]} and {@code String[]} respectively, or even any arbitrary combination 81 * thereof. 82 * 83 * @param formal The type whose type variables or itself is mapped to other type(s). It's almost 84 * always a bug if {@code formal} isn't a type variable and contains no type variable. Make 85 * sure you are passing the two parameters in the right order. 86 * @param actual The type that the formal type variable(s) are mapped to. It can be or contain yet 87 * other type variables, in which case these type variables will be further resolved if 88 * corresponding mappings exist in the current {@code TypeResolver} instance. 89 */ where(Type formal, Type actual)90 public TypeResolver where(Type formal, Type actual) { 91 Map<TypeVariableKey, Type> mappings = Maps.newHashMap(); 92 populateTypeMappings(mappings, checkNotNull(formal), checkNotNull(actual)); 93 return where(mappings); 94 } 95 96 /** Returns a new {@code TypeResolver} with {@code variable} mapping to {@code type}. */ where(Map<TypeVariableKey, ? extends Type> mappings)97 TypeResolver where(Map<TypeVariableKey, ? extends Type> mappings) { 98 return new TypeResolver(typeTable.where(mappings)); 99 } 100 populateTypeMappings( final Map<TypeVariableKey, Type> mappings, Type from, final Type to)101 private static void populateTypeMappings( 102 final Map<TypeVariableKey, Type> mappings, Type from, final Type to) { 103 if (from.equals(to)) { 104 return; 105 } 106 new TypeVisitor() { 107 @Override void visitTypeVariable(TypeVariable<?> typeVariable) { 108 mappings.put(new TypeVariableKey(typeVariable), to); 109 } 110 @Override void visitWildcardType(WildcardType fromWildcardType) { 111 WildcardType toWildcardType = expectArgument(WildcardType.class, to); 112 Type[] fromUpperBounds = fromWildcardType.getUpperBounds(); 113 Type[] toUpperBounds = toWildcardType.getUpperBounds(); 114 Type[] fromLowerBounds = fromWildcardType.getLowerBounds(); 115 Type[] toLowerBounds = toWildcardType.getLowerBounds(); 116 checkArgument( 117 fromUpperBounds.length == toUpperBounds.length 118 && fromLowerBounds.length == toLowerBounds.length, 119 "Incompatible type: %s vs. %s", fromWildcardType, to); 120 for (int i = 0; i < fromUpperBounds.length; i++) { 121 populateTypeMappings(mappings, fromUpperBounds[i], toUpperBounds[i]); 122 } 123 for (int i = 0; i < fromLowerBounds.length; i++) { 124 populateTypeMappings(mappings, fromLowerBounds[i], toLowerBounds[i]); 125 } 126 } 127 @Override void visitParameterizedType(ParameterizedType fromParameterizedType) { 128 ParameterizedType toParameterizedType = expectArgument(ParameterizedType.class, to); 129 checkArgument(fromParameterizedType.getRawType().equals(toParameterizedType.getRawType()), 130 "Inconsistent raw type: %s vs. %s", fromParameterizedType, to); 131 Type[] fromArgs = fromParameterizedType.getActualTypeArguments(); 132 Type[] toArgs = toParameterizedType.getActualTypeArguments(); 133 checkArgument(fromArgs.length == toArgs.length, 134 "%s not compatible with %s", fromParameterizedType, toParameterizedType); 135 for (int i = 0; i < fromArgs.length; i++) { 136 populateTypeMappings(mappings, fromArgs[i], toArgs[i]); 137 } 138 } 139 @Override void visitGenericArrayType(GenericArrayType fromArrayType) { 140 Type componentType = Types.getComponentType(to); 141 checkArgument(componentType != null, "%s is not an array type.", to); 142 populateTypeMappings(mappings, fromArrayType.getGenericComponentType(), componentType); 143 } 144 @Override void visitClass(Class<?> fromClass) { 145 // Can't map from a raw class to anything other than itself. 146 // You can't say "assuming String is Integer". 147 // And we don't support "assuming String is T"; user has to say "assuming T is String". 148 throw new IllegalArgumentException("No type mapping from " + fromClass); 149 } 150 }.visit(from); 151 } 152 153 /** 154 * Resolves all type variables in {@code type} and all downstream types and 155 * returns a corresponding type with type variables resolved. 156 */ resolveType(Type type)157 public Type resolveType(Type type) { 158 checkNotNull(type); 159 if (type instanceof TypeVariable) { 160 return typeTable.resolve((TypeVariable<?>) type); 161 } else if (type instanceof ParameterizedType) { 162 return resolveParameterizedType((ParameterizedType) type); 163 } else if (type instanceof GenericArrayType) { 164 return resolveGenericArrayType((GenericArrayType) type); 165 } else if (type instanceof WildcardType) { 166 return resolveWildcardType((WildcardType) type); 167 } else { 168 // if Class<?>, no resolution needed, we are done. 169 return type; 170 } 171 } 172 resolveTypes(Type[] types)173 private Type[] resolveTypes(Type[] types) { 174 Type[] result = new Type[types.length]; 175 for (int i = 0; i < types.length; i++) { 176 result[i] = resolveType(types[i]); 177 } 178 return result; 179 } 180 resolveWildcardType(WildcardType type)181 private WildcardType resolveWildcardType(WildcardType type) { 182 Type[] lowerBounds = type.getLowerBounds(); 183 Type[] upperBounds = type.getUpperBounds(); 184 return new Types.WildcardTypeImpl( 185 resolveTypes(lowerBounds), resolveTypes(upperBounds)); 186 } 187 resolveGenericArrayType(GenericArrayType type)188 private Type resolveGenericArrayType(GenericArrayType type) { 189 Type componentType = type.getGenericComponentType(); 190 Type resolvedComponentType = resolveType(componentType); 191 return Types.newArrayType(resolvedComponentType); 192 } 193 resolveParameterizedType(ParameterizedType type)194 private ParameterizedType resolveParameterizedType(ParameterizedType type) { 195 Type owner = type.getOwnerType(); 196 Type resolvedOwner = (owner == null) ? null : resolveType(owner); 197 Type resolvedRawType = resolveType(type.getRawType()); 198 199 Type[] args = type.getActualTypeArguments(); 200 Type[] resolvedArgs = resolveTypes(args); 201 return Types.newParameterizedTypeWithOwner( 202 resolvedOwner, (Class<?>) resolvedRawType, resolvedArgs); 203 } 204 expectArgument(Class<T> type, Object arg)205 private static <T> T expectArgument(Class<T> type, Object arg) { 206 try { 207 return type.cast(arg); 208 } catch (ClassCastException e) { 209 throw new IllegalArgumentException(arg + " is not a " + type.getSimpleName()); 210 } 211 } 212 213 /** A TypeTable maintains mapping from {@link TypeVariable} to types. */ 214 private static class TypeTable { 215 private final ImmutableMap<TypeVariableKey, Type> map; 216 TypeTable()217 TypeTable() { 218 this.map = ImmutableMap.of(); 219 } 220 TypeTable(ImmutableMap<TypeVariableKey, Type> map)221 private TypeTable(ImmutableMap<TypeVariableKey, Type> map) { 222 this.map = map; 223 } 224 225 /** Returns a new {@code TypeResolver} with {@code variable} mapping to {@code type}. */ where(Map<TypeVariableKey, ? extends Type> mappings)226 final TypeTable where(Map<TypeVariableKey, ? extends Type> mappings) { 227 ImmutableMap.Builder<TypeVariableKey, Type> builder = ImmutableMap.builder(); 228 builder.putAll(map); 229 for (Map.Entry<TypeVariableKey, ? extends Type> mapping : mappings.entrySet()) { 230 TypeVariableKey variable = mapping.getKey(); 231 Type type = mapping.getValue(); 232 checkArgument(!variable.equalsType(type), "Type variable %s bound to itself", variable); 233 builder.put(variable, type); 234 } 235 return new TypeTable(builder.build()); 236 } 237 resolve(final TypeVariable<?> var)238 final Type resolve(final TypeVariable<?> var) { 239 final TypeTable unguarded = this; 240 TypeTable guarded = new TypeTable() { 241 @Override public Type resolveInternal( 242 TypeVariable<?> intermediateVar, TypeTable forDependent) { 243 if (intermediateVar.getGenericDeclaration().equals(var.getGenericDeclaration())) { 244 return intermediateVar; 245 } 246 return unguarded.resolveInternal(intermediateVar, forDependent); 247 } 248 }; 249 return resolveInternal(var, guarded); 250 } 251 252 /** 253 * Resolves {@code var} using the encapsulated type mapping. If it maps to yet another 254 * non-reified type or has bounds, {@code forDependants} is used to do further resolution, which 255 * doesn't try to resolve any type variable on generic declarations that are already being 256 * resolved. 257 * 258 * <p>Should only be called and overridden by {@link #resolve(TypeVariable)}. 259 */ resolveInternal(TypeVariable<?> var, TypeTable forDependants)260 Type resolveInternal(TypeVariable<?> var, TypeTable forDependants) { 261 Type type = map.get(new TypeVariableKey(var)); 262 if (type == null) { 263 Type[] bounds = var.getBounds(); 264 if (bounds.length == 0) { 265 return var; 266 } 267 Type[] resolvedBounds = new TypeResolver(forDependants).resolveTypes(bounds); 268 /* 269 * We'd like to simply create our own TypeVariable with the newly resolved bounds. There's 270 * just one problem: Starting with JDK 7u51, the JDK TypeVariable's equals() method doesn't 271 * recognize instances of our TypeVariable implementation. This is a problem because users 272 * compare TypeVariables from the JDK against TypeVariables returned by TypeResolver. To 273 * work with all JDK versions, TypeResolver must return the appropriate TypeVariable 274 * implementation in each of the three possible cases: 275 * 276 * 1. Prior to JDK 7u51, the JDK TypeVariable implementation interoperates with ours. 277 * Therefore, we can always create our own TypeVariable. 278 * 279 * 2. Starting with JDK 7u51, the JDK TypeVariable implementations does not interoperate 280 * with ours. Therefore, we have to be careful about whether we create our own TypeVariable: 281 * 282 * 2a. If the resolved types are identical to the original types, then we can return the 283 * original, identical JDK TypeVariable. By doing so, we sidestep the problem entirely. 284 * 285 * 2b. If the resolved types are different from the original types, things are trickier. The 286 * only way to get a TypeVariable instance for the resolved types is to create our own. The 287 * created TypeVariable will not interoperate with any JDK TypeVariable. But this is OK: We 288 * don't _want_ our new TypeVariable to be equal to the JDK TypeVariable because it has 289 * _different bounds_ than the JDK TypeVariable. And it wouldn't make sense for our new 290 * TypeVariable to be equal to any _other_ JDK TypeVariable, either, because any other JDK 291 * TypeVariable must have a different declaration or name. The only TypeVariable that our 292 * new TypeVariable _will_ be equal to is an equivalent TypeVariable that was also created 293 * by us. And that equality is guaranteed to hold because it doesn't involve the JDK 294 * TypeVariable implementation at all. 295 */ 296 if (Types.NativeTypeVariableEquals.NATIVE_TYPE_VARIABLE_ONLY 297 && Arrays.equals(bounds, resolvedBounds)) { 298 return var; 299 } 300 return Types.newArtificialTypeVariable( 301 var.getGenericDeclaration(), var.getName(), resolvedBounds); 302 } 303 // in case the type is yet another type variable. 304 return new TypeResolver(forDependants).resolveType(type); 305 } 306 } 307 308 private static final class TypeMappingIntrospector extends TypeVisitor { 309 310 private static final WildcardCapturer wildcardCapturer = new WildcardCapturer(); 311 312 private final Map<TypeVariableKey, Type> mappings = Maps.newHashMap(); 313 314 /** 315 * Returns type mappings using type parameters and type arguments found in 316 * the generic superclass and the super interfaces of {@code contextClass}. 317 */ getTypeMappings( Type contextType)318 static ImmutableMap<TypeVariableKey, Type> getTypeMappings( 319 Type contextType) { 320 TypeMappingIntrospector introspector = new TypeMappingIntrospector(); 321 introspector.visit(wildcardCapturer.capture(contextType)); 322 return ImmutableMap.copyOf(introspector.mappings); 323 } 324 visitClass(Class<?> clazz)325 @Override void visitClass(Class<?> clazz) { 326 visit(clazz.getGenericSuperclass()); 327 visit(clazz.getGenericInterfaces()); 328 } 329 visitParameterizedType(ParameterizedType parameterizedType)330 @Override void visitParameterizedType(ParameterizedType parameterizedType) { 331 Class<?> rawClass = (Class<?>) parameterizedType.getRawType(); 332 TypeVariable<?>[] vars = rawClass.getTypeParameters(); 333 Type[] typeArgs = parameterizedType.getActualTypeArguments(); 334 checkState(vars.length == typeArgs.length); 335 for (int i = 0; i < vars.length; i++) { 336 map(new TypeVariableKey(vars[i]), typeArgs[i]); 337 } 338 visit(rawClass); 339 visit(parameterizedType.getOwnerType()); 340 } 341 visitTypeVariable(TypeVariable<?> t)342 @Override void visitTypeVariable(TypeVariable<?> t) { 343 visit(t.getBounds()); 344 } 345 visitWildcardType(WildcardType t)346 @Override void visitWildcardType(WildcardType t) { 347 visit(t.getUpperBounds()); 348 } 349 map(final TypeVariableKey var, final Type arg)350 private void map(final TypeVariableKey var, final Type arg) { 351 if (mappings.containsKey(var)) { 352 // Mapping already established 353 // This is possible when following both superClass -> enclosingClass 354 // and enclosingclass -> superClass paths. 355 // Since we follow the path of superclass first, enclosing second, 356 // superclass mapping should take precedence. 357 return; 358 } 359 // First, check whether var -> arg forms a cycle 360 for (Type t = arg; t != null; t = mappings.get(TypeVariableKey.forLookup(t))) { 361 if (var.equalsType(t)) { 362 // cycle detected, remove the entire cycle from the mapping so that 363 // each type variable resolves deterministically to itself. 364 // Otherwise, a F -> T cycle will end up resolving both F and T 365 // nondeterministically to either F or T. 366 for (Type x = arg; x != null; x = mappings.remove(TypeVariableKey.forLookup(x))) {} 367 return; 368 } 369 } 370 mappings.put(var, arg); 371 } 372 } 373 374 // This is needed when resolving types against a context with wildcards 375 // For example: 376 // class Holder<T> { 377 // void set(T data) {...} 378 // } 379 // Holder<List<?>> should *not* resolve the set() method to set(List<?> data). 380 // Instead, it should create a capture of the wildcard so that set() rejects any List<T>. 381 private static final class WildcardCapturer { 382 383 private final AtomicInteger id = new AtomicInteger(); 384 capture(Type type)385 Type capture(Type type) { 386 checkNotNull(type); 387 if (type instanceof Class) { 388 return type; 389 } 390 if (type instanceof TypeVariable) { 391 return type; 392 } 393 if (type instanceof GenericArrayType) { 394 GenericArrayType arrayType = (GenericArrayType) type; 395 return Types.newArrayType(capture(arrayType.getGenericComponentType())); 396 } 397 if (type instanceof ParameterizedType) { 398 ParameterizedType parameterizedType = (ParameterizedType) type; 399 return Types.newParameterizedTypeWithOwner( 400 captureNullable(parameterizedType.getOwnerType()), 401 (Class<?>) parameterizedType.getRawType(), 402 capture(parameterizedType.getActualTypeArguments())); 403 } 404 if (type instanceof WildcardType) { 405 WildcardType wildcardType = (WildcardType) type; 406 Type[] lowerBounds = wildcardType.getLowerBounds(); 407 if (lowerBounds.length == 0) { // ? extends something changes to capture-of 408 Type[] upperBounds = wildcardType.getUpperBounds(); 409 String name = "capture#" + id.incrementAndGet() + "-of ? extends " 410 + Joiner.on('&').join(upperBounds); 411 return Types.newArtificialTypeVariable( 412 WildcardCapturer.class, name, wildcardType.getUpperBounds()); 413 } else { 414 // TODO(benyu): handle ? super T somehow. 415 return type; 416 } 417 } 418 throw new AssertionError("must have been one of the known types"); 419 } 420 captureNullable(@ullable Type type)421 private Type captureNullable(@Nullable Type type) { 422 if (type == null) { 423 return null; 424 } 425 return capture(type); 426 } 427 capture(Type[] types)428 private Type[] capture(Type[] types) { 429 Type[] result = new Type[types.length]; 430 for (int i = 0; i < types.length; i++) { 431 result[i] = capture(types[i]); 432 } 433 return result; 434 } 435 } 436 437 /** 438 * Wraps around {@code TypeVariable<?>} to ensure that any two type variables are equal as long as 439 * they are declared by the same {@link java.lang.reflect.GenericDeclaration} and have the same 440 * name, even if their bounds differ. 441 * 442 * <p>While resolving a type variable from a {var -> type} map, we don't care whether the 443 * type variable's bound has been partially resolved. As long as the type variable "identity" 444 * matches. 445 * 446 * <p>On the other hand, if for example we are resolving List<A extends B> to 447 * List<A extends String>, we need to compare that <A extends B> is unequal to 448 * <A extends String> in order to decide to use the transformed type instead of the original 449 * type. 450 */ 451 static final class TypeVariableKey { 452 private final TypeVariable<?> var; 453 TypeVariableKey(TypeVariable<?> var)454 TypeVariableKey(TypeVariable<?> var) { 455 this.var = checkNotNull(var); 456 } 457 hashCode()458 @Override public int hashCode() { 459 return Objects.hashCode(var.getGenericDeclaration(), var.getName()); 460 } 461 equals(Object obj)462 @Override public boolean equals(Object obj) { 463 if (obj instanceof TypeVariableKey) { 464 TypeVariableKey that = (TypeVariableKey) obj; 465 return equalsTypeVariable(that.var); 466 } else { 467 return false; 468 } 469 } 470 toString()471 @Override public String toString() { 472 return var.toString(); 473 } 474 475 /** Wraps {@code t} in a {@code TypeVariableKey} if it's a type variable. */ forLookup(Type t)476 static Object forLookup(Type t) { 477 if (t instanceof TypeVariable) { 478 return new TypeVariableKey((TypeVariable<?>) t); 479 } else { 480 return null; 481 } 482 } 483 484 /** 485 * Returns true if {@code type} is a {@code TypeVariable} with the same name and declared by 486 * the same {@code GenericDeclaration}. 487 */ equalsType(Type type)488 boolean equalsType(Type type) { 489 if (type instanceof TypeVariable) { 490 return equalsTypeVariable((TypeVariable<?>) type); 491 } else { 492 return false; 493 } 494 } 495 equalsTypeVariable(TypeVariable<?> that)496 private boolean equalsTypeVariable(TypeVariable<?> that) { 497 return var.getGenericDeclaration().equals(that.getGenericDeclaration()) 498 && var.getName().equals(that.getName()); 499 } 500 } 501 } 502