001/* 002 * Copyright (C) 2009 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 005 * in compliance with the License. You may obtain a copy of the License at 006 * 007 * http://www.apache.org/licenses/LICENSE-2.0 008 * 009 * Unless required by applicable law or agreed to in writing, software distributed under the License 010 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 011 * or implied. See the License for the specific language governing permissions and limitations under 012 * the License. 013 */ 014 015package com.google.common.reflect; 016 017import static com.google.common.base.Preconditions.checkArgument; 018import static com.google.common.base.Preconditions.checkNotNull; 019import static com.google.common.base.Preconditions.checkState; 020 021import com.google.common.annotations.Beta; 022import com.google.common.base.Joiner; 023import com.google.common.base.Objects; 024import com.google.common.collect.ImmutableMap; 025import com.google.common.collect.Maps; 026import java.lang.reflect.GenericArrayType; 027import java.lang.reflect.ParameterizedType; 028import java.lang.reflect.Type; 029import java.lang.reflect.TypeVariable; 030import java.lang.reflect.WildcardType; 031import java.util.Arrays; 032import java.util.Map; 033import java.util.concurrent.atomic.AtomicInteger; 034import javax.annotation.Nullable; 035 036/** 037 * An object of this class encapsulates type mappings from type variables. Mappings are established 038 * with {@link #where} and types are resolved using {@link #resolveType}. 039 * 040 * <p>Note that usually type mappings are already implied by the static type hierarchy (for example, 041 * the {@code E} type variable declared by class {@code List} naturally maps to {@code String} in 042 * the context of {@code class MyStringList implements List<String>}. In such case, prefer to use 043 * {@link TypeToken#resolveType} since it's simpler and more type safe. This class should only be 044 * used when the type mapping isn't implied by the static type hierarchy, but provided through other 045 * means such as an annotation or external configuration file. 046 * 047 * @author Ben Yu 048 * @since 15.0 049 */ 050@Beta 051public final class TypeResolver { 052 053 private final TypeTable typeTable; 054 055 public TypeResolver() { 056 this.typeTable = new TypeTable(); 057 } 058 059 private TypeResolver(TypeTable typeTable) { 060 this.typeTable = typeTable; 061 } 062 063 static TypeResolver accordingTo(Type type) { 064 return new TypeResolver().where(TypeMappingIntrospector.getTypeMappings(type)); 065 } 066 067 /** 068 * Returns a new {@code TypeResolver} with type variables in {@code formal} mapping to types in 069 * {@code actual}. 070 * 071 * <p>For example, if {@code formal} is a {@code TypeVariable T}, and {@code actual} is {@code 072 * String.class}, then {@code new TypeResolver().where(formal, actual)} will 073 * {@linkplain #resolveType resolve} {@code ParameterizedType List<T>} to {@code List<String>}, 074 * and resolve {@code Map<T, Something>} to {@code Map<String, Something>} etc. Similarly, 075 * {@code formal} and {@code actual} can be {@code Map<K, V>} and {@code Map<String, Integer>} 076 * respectively, or they can be {@code E[]} and {@code String[]} respectively, or even any 077 * arbitrary combination thereof. 078 * 079 * @param formal The type whose type variables or itself is mapped to other type(s). It's almost 080 * always a bug if {@code formal} isn't a type variable and contains no type variable. Make 081 * sure you are passing the two parameters in the right order. 082 * @param actual The type that the formal type variable(s) are mapped to. It can be or contain yet 083 * other type variables, in which case these type variables will be further resolved if 084 * corresponding mappings exist in the current {@code TypeResolver} instance. 085 */ 086 public TypeResolver where(Type formal, Type actual) { 087 Map<TypeVariableKey, Type> mappings = Maps.newHashMap(); 088 populateTypeMappings(mappings, checkNotNull(formal), checkNotNull(actual)); 089 return where(mappings); 090 } 091 092 /** Returns a new {@code TypeResolver} with {@code variable} mapping to {@code type}. */ 093 TypeResolver where(Map<TypeVariableKey, ? extends Type> mappings) { 094 return new TypeResolver(typeTable.where(mappings)); 095 } 096 097 private static void populateTypeMappings( 098 final Map<TypeVariableKey, Type> mappings, Type from, final Type to) { 099 if (from.equals(to)) { 100 return; 101 } 102 new TypeVisitor() { 103 @Override 104 void visitTypeVariable(TypeVariable<?> typeVariable) { 105 mappings.put(new TypeVariableKey(typeVariable), to); 106 } 107 108 @Override 109 void visitWildcardType(WildcardType fromWildcardType) { 110 if (!(to instanceof WildcardType)) { 111 return; // okay to say <?> is anything 112 } 113 WildcardType toWildcardType = (WildcardType) to; 114 Type[] fromUpperBounds = fromWildcardType.getUpperBounds(); 115 Type[] toUpperBounds = toWildcardType.getUpperBounds(); 116 Type[] fromLowerBounds = fromWildcardType.getLowerBounds(); 117 Type[] toLowerBounds = toWildcardType.getLowerBounds(); 118 checkArgument( 119 fromUpperBounds.length == toUpperBounds.length 120 && fromLowerBounds.length == toLowerBounds.length, 121 "Incompatible type: %s vs. %s", 122 fromWildcardType, 123 to); 124 for (int i = 0; i < fromUpperBounds.length; i++) { 125 populateTypeMappings(mappings, fromUpperBounds[i], toUpperBounds[i]); 126 } 127 for (int i = 0; i < fromLowerBounds.length; i++) { 128 populateTypeMappings(mappings, fromLowerBounds[i], toLowerBounds[i]); 129 } 130 } 131 132 @Override 133 void visitParameterizedType(ParameterizedType fromParameterizedType) { 134 if (to instanceof WildcardType) { 135 return; // Okay to say Foo<A> is <?> 136 } 137 ParameterizedType toParameterizedType = expectArgument(ParameterizedType.class, to); 138 if (fromParameterizedType.getOwnerType() != null 139 && toParameterizedType.getOwnerType() != null) { 140 populateTypeMappings( 141 mappings, fromParameterizedType.getOwnerType(), toParameterizedType.getOwnerType()); 142 } 143 checkArgument( 144 fromParameterizedType.getRawType().equals(toParameterizedType.getRawType()), 145 "Inconsistent raw type: %s vs. %s", 146 fromParameterizedType, 147 to); 148 Type[] fromArgs = fromParameterizedType.getActualTypeArguments(); 149 Type[] toArgs = toParameterizedType.getActualTypeArguments(); 150 checkArgument( 151 fromArgs.length == toArgs.length, 152 "%s not compatible with %s", 153 fromParameterizedType, 154 toParameterizedType); 155 for (int i = 0; i < fromArgs.length; i++) { 156 populateTypeMappings(mappings, fromArgs[i], toArgs[i]); 157 } 158 } 159 160 @Override 161 void visitGenericArrayType(GenericArrayType fromArrayType) { 162 if (to instanceof WildcardType) { 163 return; // Okay to say A[] is <?> 164 } 165 Type componentType = Types.getComponentType(to); 166 checkArgument(componentType != null, "%s is not an array type.", to); 167 populateTypeMappings(mappings, fromArrayType.getGenericComponentType(), componentType); 168 } 169 170 @Override 171 void visitClass(Class<?> fromClass) { 172 if (to instanceof WildcardType) { 173 return; // Okay to say Foo is <?> 174 } 175 // Can't map from a raw class to anything other than itself or a wildcard. 176 // You can't say "assuming String is Integer". 177 // And we don't support "assuming String is T"; user has to say "assuming T is String". 178 throw new IllegalArgumentException("No type mapping from " + fromClass + " to " + to); 179 } 180 }.visit(from); 181 } 182 183 /** 184 * Resolves all type variables in {@code type} and all downstream types and returns a 185 * corresponding type with type variables resolved. 186 */ 187 public Type resolveType(Type type) { 188 checkNotNull(type); 189 if (type instanceof TypeVariable) { 190 return typeTable.resolve((TypeVariable<?>) type); 191 } else if (type instanceof ParameterizedType) { 192 return resolveParameterizedType((ParameterizedType) type); 193 } else if (type instanceof GenericArrayType) { 194 return resolveGenericArrayType((GenericArrayType) type); 195 } else if (type instanceof WildcardType) { 196 return resolveWildcardType((WildcardType) type); 197 } else { 198 // if Class<?>, no resolution needed, we are done. 199 return type; 200 } 201 } 202 203 private Type[] resolveTypes(Type[] types) { 204 Type[] result = new Type[types.length]; 205 for (int i = 0; i < types.length; i++) { 206 result[i] = resolveType(types[i]); 207 } 208 return result; 209 } 210 211 private WildcardType resolveWildcardType(WildcardType type) { 212 Type[] lowerBounds = type.getLowerBounds(); 213 Type[] upperBounds = type.getUpperBounds(); 214 return new Types.WildcardTypeImpl(resolveTypes(lowerBounds), resolveTypes(upperBounds)); 215 } 216 217 private Type resolveGenericArrayType(GenericArrayType type) { 218 Type componentType = type.getGenericComponentType(); 219 Type resolvedComponentType = resolveType(componentType); 220 return Types.newArrayType(resolvedComponentType); 221 } 222 223 private ParameterizedType resolveParameterizedType(ParameterizedType type) { 224 Type owner = type.getOwnerType(); 225 Type resolvedOwner = (owner == null) ? null : resolveType(owner); 226 Type resolvedRawType = resolveType(type.getRawType()); 227 228 Type[] args = type.getActualTypeArguments(); 229 Type[] resolvedArgs = resolveTypes(args); 230 return Types.newParameterizedTypeWithOwner( 231 resolvedOwner, (Class<?>) resolvedRawType, resolvedArgs); 232 } 233 234 private static <T> T expectArgument(Class<T> type, Object arg) { 235 try { 236 return type.cast(arg); 237 } catch (ClassCastException e) { 238 throw new IllegalArgumentException(arg + " is not a " + type.getSimpleName()); 239 } 240 } 241 242 /** A TypeTable maintains mapping from {@link TypeVariable} to types. */ 243 private static class TypeTable { 244 private final ImmutableMap<TypeVariableKey, Type> map; 245 246 TypeTable() { 247 this.map = ImmutableMap.of(); 248 } 249 250 private TypeTable(ImmutableMap<TypeVariableKey, Type> map) { 251 this.map = map; 252 } 253 254 /** Returns a new {@code TypeResolver} with {@code variable} mapping to {@code type}. */ 255 final TypeTable where(Map<TypeVariableKey, ? extends Type> mappings) { 256 ImmutableMap.Builder<TypeVariableKey, Type> builder = ImmutableMap.builder(); 257 builder.putAll(map); 258 for (Map.Entry<TypeVariableKey, ? extends Type> mapping : mappings.entrySet()) { 259 TypeVariableKey variable = mapping.getKey(); 260 Type type = mapping.getValue(); 261 checkArgument(!variable.equalsType(type), "Type variable %s bound to itself", variable); 262 builder.put(variable, type); 263 } 264 return new TypeTable(builder.build()); 265 } 266 267 final Type resolve(final TypeVariable<?> var) { 268 final TypeTable unguarded = this; 269 TypeTable guarded = 270 new TypeTable() { 271 @Override 272 public Type resolveInternal(TypeVariable<?> intermediateVar, TypeTable forDependent) { 273 if (intermediateVar.getGenericDeclaration().equals(var.getGenericDeclaration())) { 274 return intermediateVar; 275 } 276 return unguarded.resolveInternal(intermediateVar, forDependent); 277 } 278 }; 279 return resolveInternal(var, guarded); 280 } 281 282 /** 283 * Resolves {@code var} using the encapsulated type mapping. If it maps to yet another 284 * non-reified type or has bounds, {@code forDependants} is used to do further resolution, which 285 * doesn't try to resolve any type variable on generic declarations that are already being 286 * resolved. 287 * 288 * <p>Should only be called and overridden by {@link #resolve(TypeVariable)}. 289 */ 290 Type resolveInternal(TypeVariable<?> var, TypeTable forDependants) { 291 Type type = map.get(new TypeVariableKey(var)); 292 if (type == null) { 293 Type[] bounds = var.getBounds(); 294 if (bounds.length == 0) { 295 return var; 296 } 297 Type[] resolvedBounds = new TypeResolver(forDependants).resolveTypes(bounds); 298 /* 299 * We'd like to simply create our own TypeVariable with the newly resolved bounds. There's 300 * just one problem: Starting with JDK 7u51, the JDK TypeVariable's equals() method doesn't 301 * recognize instances of our TypeVariable implementation. This is a problem because users 302 * compare TypeVariables from the JDK against TypeVariables returned by TypeResolver. To 303 * work with all JDK versions, TypeResolver must return the appropriate TypeVariable 304 * implementation in each of the three possible cases: 305 * 306 * 1. Prior to JDK 7u51, the JDK TypeVariable implementation interoperates with ours. 307 * Therefore, we can always create our own TypeVariable. 308 * 309 * 2. Starting with JDK 7u51, the JDK TypeVariable implementations does not interoperate 310 * with ours. Therefore, we have to be careful about whether we create our own TypeVariable: 311 * 312 * 2a. If the resolved types are identical to the original types, then we can return the 313 * original, identical JDK TypeVariable. By doing so, we sidestep the problem entirely. 314 * 315 * 2b. If the resolved types are different from the original types, things are trickier. The 316 * only way to get a TypeVariable instance for the resolved types is to create our own. The 317 * created TypeVariable will not interoperate with any JDK TypeVariable. But this is OK: We 318 * don't _want_ our new TypeVariable to be equal to the JDK TypeVariable because it has 319 * _different bounds_ than the JDK TypeVariable. And it wouldn't make sense for our new 320 * TypeVariable to be equal to any _other_ JDK TypeVariable, either, because any other JDK 321 * TypeVariable must have a different declaration or name. The only TypeVariable that our 322 * new TypeVariable _will_ be equal to is an equivalent TypeVariable that was also created 323 * by us. And that equality is guaranteed to hold because it doesn't involve the JDK 324 * TypeVariable implementation at all. 325 */ 326 if (Types.NativeTypeVariableEquals.NATIVE_TYPE_VARIABLE_ONLY 327 && Arrays.equals(bounds, resolvedBounds)) { 328 return var; 329 } 330 return Types.newArtificialTypeVariable( 331 var.getGenericDeclaration(), var.getName(), resolvedBounds); 332 } 333 // in case the type is yet another type variable. 334 return new TypeResolver(forDependants).resolveType(type); 335 } 336 } 337 338 private static final class TypeMappingIntrospector extends TypeVisitor { 339 340 private static final WildcardCapturer wildcardCapturer = new WildcardCapturer(); 341 342 private final Map<TypeVariableKey, Type> mappings = Maps.newHashMap(); 343 344 /** 345 * Returns type mappings using type parameters and type arguments found in the generic 346 * superclass and the super interfaces of {@code contextClass}. 347 */ 348 static ImmutableMap<TypeVariableKey, Type> getTypeMappings(Type contextType) { 349 TypeMappingIntrospector introspector = new TypeMappingIntrospector(); 350 introspector.visit(wildcardCapturer.capture(contextType)); 351 return ImmutableMap.copyOf(introspector.mappings); 352 } 353 354 @Override 355 void visitClass(Class<?> clazz) { 356 visit(clazz.getGenericSuperclass()); 357 visit(clazz.getGenericInterfaces()); 358 } 359 360 @Override 361 void visitParameterizedType(ParameterizedType parameterizedType) { 362 Class<?> rawClass = (Class<?>) parameterizedType.getRawType(); 363 TypeVariable<?>[] vars = rawClass.getTypeParameters(); 364 Type[] typeArgs = parameterizedType.getActualTypeArguments(); 365 checkState(vars.length == typeArgs.length); 366 for (int i = 0; i < vars.length; i++) { 367 map(new TypeVariableKey(vars[i]), typeArgs[i]); 368 } 369 visit(rawClass); 370 visit(parameterizedType.getOwnerType()); 371 } 372 373 @Override 374 void visitTypeVariable(TypeVariable<?> t) { 375 visit(t.getBounds()); 376 } 377 378 @Override 379 void visitWildcardType(WildcardType t) { 380 visit(t.getUpperBounds()); 381 } 382 383 private void map(final TypeVariableKey var, final Type arg) { 384 if (mappings.containsKey(var)) { 385 // Mapping already established 386 // This is possible when following both superClass -> enclosingClass 387 // and enclosingclass -> superClass paths. 388 // Since we follow the path of superclass first, enclosing second, 389 // superclass mapping should take precedence. 390 return; 391 } 392 // First, check whether var -> arg forms a cycle 393 for (Type t = arg; t != null; t = mappings.get(TypeVariableKey.forLookup(t))) { 394 if (var.equalsType(t)) { 395 // cycle detected, remove the entire cycle from the mapping so that 396 // each type variable resolves deterministically to itself. 397 // Otherwise, a F -> T cycle will end up resolving both F and T 398 // nondeterministically to either F or T. 399 for (Type x = arg; x != null; x = mappings.remove(TypeVariableKey.forLookup(x))) {} 400 return; 401 } 402 } 403 mappings.put(var, arg); 404 } 405 } 406 407 // This is needed when resolving types against a context with wildcards 408 // For example: 409 // class Holder<T> { 410 // void set(T data) {...} 411 // } 412 // Holder<List<?>> should *not* resolve the set() method to set(List<?> data). 413 // Instead, it should create a capture of the wildcard so that set() rejects any List<T>. 414 private static final class WildcardCapturer { 415 416 private final AtomicInteger id = new AtomicInteger(); 417 418 Type capture(Type type) { 419 checkNotNull(type); 420 if (type instanceof Class) { 421 return type; 422 } 423 if (type instanceof TypeVariable) { 424 return type; 425 } 426 if (type instanceof GenericArrayType) { 427 GenericArrayType arrayType = (GenericArrayType) type; 428 return Types.newArrayType(capture(arrayType.getGenericComponentType())); 429 } 430 if (type instanceof ParameterizedType) { 431 ParameterizedType parameterizedType = (ParameterizedType) type; 432 return Types.newParameterizedTypeWithOwner( 433 captureNullable(parameterizedType.getOwnerType()), 434 (Class<?>) parameterizedType.getRawType(), 435 capture(parameterizedType.getActualTypeArguments())); 436 } 437 if (type instanceof WildcardType) { 438 WildcardType wildcardType = (WildcardType) type; 439 Type[] lowerBounds = wildcardType.getLowerBounds(); 440 if (lowerBounds.length == 0) { // ? extends something changes to capture-of 441 Type[] upperBounds = wildcardType.getUpperBounds(); 442 String name = 443 "capture#" 444 + id.incrementAndGet() 445 + "-of ? extends " 446 + Joiner.on('&').join(upperBounds); 447 return Types.newArtificialTypeVariable( 448 WildcardCapturer.class, name, wildcardType.getUpperBounds()); 449 } else { 450 // TODO(benyu): handle ? super T somehow. 451 return type; 452 } 453 } 454 throw new AssertionError("must have been one of the known types"); 455 } 456 457 private Type captureNullable(@Nullable Type type) { 458 if (type == null) { 459 return null; 460 } 461 return capture(type); 462 } 463 464 private Type[] capture(Type[] types) { 465 Type[] result = new Type[types.length]; 466 for (int i = 0; i < types.length; i++) { 467 result[i] = capture(types[i]); 468 } 469 return result; 470 } 471 } 472 473 /** 474 * Wraps around {@code TypeVariable<?>} to ensure that any two type variables are equal as long as 475 * they are declared by the same {@link java.lang.reflect.GenericDeclaration} and have the same 476 * name, even if their bounds differ. 477 * 478 * <p>While resolving a type variable from a {@code var -> type} map, we don't care whether the 479 * type variable's bound has been partially resolved. As long as the type variable "identity" 480 * matches. 481 * 482 * <p>On the other hand, if for example we are resolving {@code List<A extends B>} to {@code 483 * List<A extends String>}, we need to compare that {@code <A extends B>} is unequal to {@code <A 484 * extends String>} in order to decide to use the transformed type instead of the original type. 485 */ 486 static final class TypeVariableKey { 487 private final TypeVariable<?> var; 488 489 TypeVariableKey(TypeVariable<?> var) { 490 this.var = checkNotNull(var); 491 } 492 493 @Override 494 public int hashCode() { 495 return Objects.hashCode(var.getGenericDeclaration(), var.getName()); 496 } 497 498 @Override 499 public boolean equals(Object obj) { 500 if (obj instanceof TypeVariableKey) { 501 TypeVariableKey that = (TypeVariableKey) obj; 502 return equalsTypeVariable(that.var); 503 } else { 504 return false; 505 } 506 } 507 508 @Override 509 public String toString() { 510 return var.toString(); 511 } 512 513 /** Wraps {@code t} in a {@code TypeVariableKey} if it's a type variable. */ 514 static TypeVariableKey forLookup(Type t) { 515 if (t instanceof TypeVariable) { 516 return new TypeVariableKey((TypeVariable<?>) t); 517 } else { 518 return null; 519 } 520 } 521 522 /** 523 * Returns true if {@code type} is a {@code TypeVariable} with the same name and declared by the 524 * same {@code GenericDeclaration}. 525 */ 526 boolean equalsType(Type type) { 527 if (type instanceof TypeVariable) { 528 return equalsTypeVariable((TypeVariable<?>) type); 529 } else { 530 return false; 531 } 532 } 533 534 private boolean equalsTypeVariable(TypeVariable<?> that) { 535 return var.getGenericDeclaration().equals(that.getGenericDeclaration()) 536 && var.getName().equals(that.getName()); 537 } 538 } 539}