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