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