Coverage Summary for Class: Types (com.google.common.reflect)
| Class | Method, % | Line, % |
|---|---|---|
| Types | 82.4% (14/17) | 69.2% (36/52) |
| Types$1 | 100% (2/2) | 100% (2/2) |
| Types$2 | 60% (3/5) | 55.6% (5/9) |
| Types$ClassOwnership | 100% (3/3) | 90.9% (10/11) |
| Types$ClassOwnership$1 | 100% (2/2) | 100% (2/2) |
| Types$ClassOwnership$1LocalClass | 100% (1/1) | 100% (1/1) |
| Types$ClassOwnership$2 | 100% (2/2) | 100% (4/4) |
| Types$ClassOwnership$3 | 100% (1/1) | 100% (1/1) |
| Types$GenericArrayTypeImpl | 80% (4/5) | 60% (6/10) |
| Types$JavaVersion | 60% (3/5) | 71.4% (15/21) |
| Types$JavaVersion$1 | 33.3% (1/3) | 12.5% (1/8) |
| Types$JavaVersion$2 | 100% (3/3) | 80% (4/5) |
| Types$JavaVersion$3 | 100% (4/4) | 45.5% (5/11) |
| Types$JavaVersion$4 | 100% (5/5) | 100% (5/5) |
| Types$JavaVersion$5 | 100% (1/1) | 100% (1/1) |
| Types$JavaVersion$6 | 0% (0/1) | 0% (0/1) |
| Types$NativeTypeVariableEquals | 50% (1/2) | 75% (3/4) |
| Types$ParameterizedTypeImpl | 85.7% (6/7) | 75.9% (22/29) |
| Types$TypeVariableImpl | 62.5% (5/8) | 35.7% (10/28) |
| Types$TypeVariableInvocationHandler | 75% (3/4) | 75% (15/20) |
| Types$WildcardTypeImpl | 100% (6/6) | 95.5% (21/22) |
| Total | 80.5% (70/87) | 68.4% (169/247) |
1 /* 2 * Copyright (C) 2011 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the License 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 * or implied. See the License for the specific language governing permissions and limitations under 12 * the License. 13 */ 14 15 package com.google.common.reflect; 16 17 import static com.google.common.base.Preconditions.checkArgument; 18 import static com.google.common.base.Preconditions.checkNotNull; 19 import static com.google.common.collect.Iterables.transform; 20 import static java.util.Objects.requireNonNull; 21 22 import com.google.common.annotations.VisibleForTesting; 23 import com.google.common.base.Function; 24 import com.google.common.base.Joiner; 25 import com.google.common.base.Objects; 26 import com.google.common.base.Predicates; 27 import com.google.common.collect.ImmutableList; 28 import com.google.common.collect.ImmutableMap; 29 import com.google.common.collect.Iterables; 30 import java.io.Serializable; 31 import java.lang.reflect.AnnotatedElement; 32 import java.lang.reflect.Array; 33 import java.lang.reflect.GenericArrayType; 34 import java.lang.reflect.GenericDeclaration; 35 import java.lang.reflect.InvocationHandler; 36 import java.lang.reflect.InvocationTargetException; 37 import java.lang.reflect.Method; 38 import java.lang.reflect.ParameterizedType; 39 import java.lang.reflect.Proxy; 40 import java.lang.reflect.Type; 41 import java.lang.reflect.TypeVariable; 42 import java.lang.reflect.WildcardType; 43 import java.security.AccessControlException; 44 import java.util.Arrays; 45 import java.util.Collection; 46 import java.util.Map.Entry; 47 import java.util.concurrent.atomic.AtomicReference; 48 import javax.annotation.CheckForNull; 49 import org.checkerframework.checker.nullness.qual.Nullable; 50 51 /** 52 * Utilities for working with {@link Type}. 53 * 54 * @author Ben Yu 55 */ 56 @ElementTypesAreNonnullByDefault 57 final class Types { 58 59 /** Class#toString without the "class " and "interface " prefixes */ 60 private static final Function<Type, String> TYPE_NAME = 61 new Function<Type, String>() { 62 @Override 63 public String apply(Type from) { 64 return JavaVersion.CURRENT.typeName(from); 65 } 66 }; 67 68 private static final Joiner COMMA_JOINER = Joiner.on(", ").useForNull("null"); 69 70 /** Returns the array type of {@code componentType}. */ 71 static Type newArrayType(Type componentType) { 72 if (componentType instanceof WildcardType) { 73 WildcardType wildcard = (WildcardType) componentType; 74 Type[] lowerBounds = wildcard.getLowerBounds(); 75 checkArgument(lowerBounds.length <= 1, "Wildcard cannot have more than one lower bounds."); 76 if (lowerBounds.length == 1) { 77 return supertypeOf(newArrayType(lowerBounds[0])); 78 } else { 79 Type[] upperBounds = wildcard.getUpperBounds(); 80 checkArgument(upperBounds.length == 1, "Wildcard should have only one upper bound."); 81 return subtypeOf(newArrayType(upperBounds[0])); 82 } 83 } 84 return JavaVersion.CURRENT.newArrayType(componentType); 85 } 86 87 /** 88 * Returns a type where {@code rawType} is parameterized by {@code arguments} and is owned by 89 * {@code ownerType}. 90 */ 91 static ParameterizedType newParameterizedTypeWithOwner( 92 @CheckForNull Type ownerType, Class<?> rawType, Type... arguments) { 93 if (ownerType == null) { 94 return newParameterizedType(rawType, arguments); 95 } 96 // ParameterizedTypeImpl constructor already checks, but we want to throw NPE before IAE 97 checkNotNull(arguments); 98 checkArgument(rawType.getEnclosingClass() != null, "Owner type for unenclosed %s", rawType); 99 return new ParameterizedTypeImpl(ownerType, rawType, arguments); 100 } 101 102 /** Returns a type where {@code rawType} is parameterized by {@code arguments}. */ 103 static ParameterizedType newParameterizedType(Class<?> rawType, Type... arguments) { 104 return new ParameterizedTypeImpl( 105 ClassOwnership.JVM_BEHAVIOR.getOwnerType(rawType), rawType, arguments); 106 } 107 108 /** Decides what owner type to use for constructing {@link ParameterizedType} from a raw class. */ 109 private enum ClassOwnership { 110 OWNED_BY_ENCLOSING_CLASS { 111 @Override 112 @CheckForNull 113 Class<?> getOwnerType(Class<?> rawType) { 114 return rawType.getEnclosingClass(); 115 } 116 }, 117 LOCAL_CLASS_HAS_NO_OWNER { 118 @Override 119 @CheckForNull 120 Class<?> getOwnerType(Class<?> rawType) { 121 if (rawType.isLocalClass()) { 122 return null; 123 } else { 124 return rawType.getEnclosingClass(); 125 } 126 } 127 }; 128 129 @CheckForNull 130 abstract Class<?> getOwnerType(Class<?> rawType); 131 132 static final ClassOwnership JVM_BEHAVIOR = detectJvmBehavior(); 133 134 private static ClassOwnership detectJvmBehavior() { 135 class LocalClass<T> {} 136 Class<?> subclass = new LocalClass<String>() {}.getClass(); 137 // requireNonNull is safe because we're examining a type that's known to have a superclass. 138 ParameterizedType parameterizedType = 139 requireNonNull((ParameterizedType) subclass.getGenericSuperclass()); 140 for (ClassOwnership behavior : ClassOwnership.values()) { 141 if (behavior.getOwnerType(LocalClass.class) == parameterizedType.getOwnerType()) { 142 return behavior; 143 } 144 } 145 throw new AssertionError(); 146 } 147 } 148 149 /** 150 * Returns a new {@link TypeVariable} that belongs to {@code declaration} with {@code name} and 151 * {@code bounds}. 152 */ 153 static <D extends GenericDeclaration> TypeVariable<D> newArtificialTypeVariable( 154 D declaration, String name, Type... bounds) { 155 return newTypeVariableImpl( 156 declaration, name, (bounds.length == 0) ? new Type[] {Object.class} : bounds); 157 } 158 159 /** Returns a new {@link WildcardType} with {@code upperBound}. */ 160 @VisibleForTesting 161 static WildcardType subtypeOf(Type upperBound) { 162 return new WildcardTypeImpl(new Type[0], new Type[] {upperBound}); 163 } 164 165 /** Returns a new {@link WildcardType} with {@code lowerBound}. */ 166 @VisibleForTesting 167 static WildcardType supertypeOf(Type lowerBound) { 168 return new WildcardTypeImpl(new Type[] {lowerBound}, new Type[] {Object.class}); 169 } 170 171 /** 172 * Returns human readable string representation of {@code type}. 173 * 174 * <p>The format is subject to change. 175 */ 176 static String toString(Type type) { 177 return (type instanceof Class) ? ((Class<?>) type).getName() : type.toString(); 178 } 179 180 @CheckForNull 181 static Type getComponentType(Type type) { 182 checkNotNull(type); 183 final AtomicReference<@Nullable Type> result = new AtomicReference<>(); 184 new TypeVisitor() { 185 @Override 186 void visitTypeVariable(TypeVariable<?> t) { 187 result.set(subtypeOfComponentType(t.getBounds())); 188 } 189 190 @Override 191 void visitWildcardType(WildcardType t) { 192 result.set(subtypeOfComponentType(t.getUpperBounds())); 193 } 194 195 @Override 196 void visitGenericArrayType(GenericArrayType t) { 197 result.set(t.getGenericComponentType()); 198 } 199 200 @Override 201 void visitClass(Class<?> t) { 202 result.set(t.getComponentType()); 203 } 204 }.visit(type); 205 return result.get(); 206 } 207 208 /** 209 * Returns {@code ? extends X} if any of {@code bounds} is a subtype of {@code X[]}; or null 210 * otherwise. 211 */ 212 @CheckForNull 213 private static Type subtypeOfComponentType(Type[] bounds) { 214 for (Type bound : bounds) { 215 Type componentType = getComponentType(bound); 216 if (componentType != null) { 217 // Only the first bound can be a class or array. 218 // Bounds after the first can only be interfaces. 219 if (componentType instanceof Class) { 220 Class<?> componentClass = (Class<?>) componentType; 221 if (componentClass.isPrimitive()) { 222 return componentClass; 223 } 224 } 225 return subtypeOf(componentType); 226 } 227 } 228 return null; 229 } 230 231 private static final class GenericArrayTypeImpl implements GenericArrayType, Serializable { 232 233 private final Type componentType; 234 235 GenericArrayTypeImpl(Type componentType) { 236 this.componentType = JavaVersion.CURRENT.usedInGenericType(componentType); 237 } 238 239 @Override 240 public Type getGenericComponentType() { 241 return componentType; 242 } 243 244 @Override 245 public String toString() { 246 return Types.toString(componentType) + "[]"; 247 } 248 249 @Override 250 public int hashCode() { 251 return componentType.hashCode(); 252 } 253 254 @Override 255 public boolean equals(@CheckForNull Object obj) { 256 if (obj instanceof GenericArrayType) { 257 GenericArrayType that = (GenericArrayType) obj; 258 return Objects.equal(getGenericComponentType(), that.getGenericComponentType()); 259 } 260 return false; 261 } 262 263 private static final long serialVersionUID = 0; 264 } 265 266 private static final class ParameterizedTypeImpl implements ParameterizedType, Serializable { 267 268 @CheckForNull private final Type ownerType; 269 private final ImmutableList<Type> argumentsList; 270 private final Class<?> rawType; 271 272 ParameterizedTypeImpl(@CheckForNull Type ownerType, Class<?> rawType, Type[] typeArguments) { 273 checkNotNull(rawType); 274 checkArgument(typeArguments.length == rawType.getTypeParameters().length); 275 disallowPrimitiveType(typeArguments, "type parameter"); 276 this.ownerType = ownerType; 277 this.rawType = rawType; 278 this.argumentsList = JavaVersion.CURRENT.usedInGenericType(typeArguments); 279 } 280 281 @Override 282 public Type[] getActualTypeArguments() { 283 return toArray(argumentsList); 284 } 285 286 @Override 287 public Type getRawType() { 288 return rawType; 289 } 290 291 @Override 292 @CheckForNull 293 public Type getOwnerType() { 294 return ownerType; 295 } 296 297 @Override 298 public String toString() { 299 StringBuilder builder = new StringBuilder(); 300 if (ownerType != null && JavaVersion.CURRENT.jdkTypeDuplicatesOwnerName()) { 301 builder.append(JavaVersion.CURRENT.typeName(ownerType)).append('.'); 302 } 303 return builder 304 .append(rawType.getName()) 305 .append('<') 306 .append(COMMA_JOINER.join(transform(argumentsList, TYPE_NAME))) 307 .append('>') 308 .toString(); 309 } 310 311 @Override 312 public int hashCode() { 313 return (ownerType == null ? 0 : ownerType.hashCode()) 314 ^ argumentsList.hashCode() 315 ^ rawType.hashCode(); 316 } 317 318 @Override 319 public boolean equals(@CheckForNull Object other) { 320 if (!(other instanceof ParameterizedType)) { 321 return false; 322 } 323 ParameterizedType that = (ParameterizedType) other; 324 return getRawType().equals(that.getRawType()) 325 && Objects.equal(getOwnerType(), that.getOwnerType()) 326 && Arrays.equals(getActualTypeArguments(), that.getActualTypeArguments()); 327 } 328 329 private static final long serialVersionUID = 0; 330 } 331 332 private static <D extends GenericDeclaration> TypeVariable<D> newTypeVariableImpl( 333 D genericDeclaration, String name, Type[] bounds) { 334 TypeVariableImpl<D> typeVariableImpl = 335 new TypeVariableImpl<D>(genericDeclaration, name, bounds); 336 @SuppressWarnings("unchecked") 337 TypeVariable<D> typeVariable = 338 Reflection.newProxy( 339 TypeVariable.class, new TypeVariableInvocationHandler(typeVariableImpl)); 340 return typeVariable; 341 } 342 343 /** 344 * Invocation handler to work around a compatibility problem between Java 7 and Java 8. 345 * 346 * <p>Java 8 introduced a new method {@code getAnnotatedBounds()} in the {@link TypeVariable} 347 * interface, whose return type {@code AnnotatedType[]} is also new in Java 8. That means that we 348 * cannot implement that interface in source code in a way that will compile on both Java 7 and 349 * Java 8. If we include the {@code getAnnotatedBounds()} method then its return type means it 350 * won't compile on Java 7, while if we don't include the method then the compiler will complain 351 * that an abstract method is unimplemented. So instead we use a dynamic proxy to get an 352 * implementation. If the method being called on the {@code TypeVariable} instance has the same 353 * name as one of the public methods of {@link TypeVariableImpl}, the proxy calls the same method 354 * on its instance of {@code TypeVariableImpl}. Otherwise it throws {@link 355 * UnsupportedOperationException}; this should only apply to {@code getAnnotatedBounds()}. This 356 * does mean that users on Java 8 who obtain an instance of {@code TypeVariable} from {@link 357 * TypeResolver#resolveType} will not be able to call {@code getAnnotatedBounds()} on it, but that 358 * should hopefully be rare. 359 * 360 * <p>TODO(b/147144588): We are currently also missing the methods inherited from {@link 361 * AnnotatedElement}, which {@code TypeVariable} began to extend only in Java 8. Those methods 362 * refer only to types present in Java 7, so we could implement them in {@code TypeVariableImpl} 363 * today. (We could probably then make {@code TypeVariableImpl} implement {@code AnnotatedElement} 364 * so that we get partial compile-time checking.) 365 * 366 * <p>This workaround should be removed at a distant future time when we no longer support Java 367 * versions earlier than 8. 368 */ 369 private static final class TypeVariableInvocationHandler implements InvocationHandler { 370 private static final ImmutableMap<String, Method> typeVariableMethods; 371 372 static { 373 ImmutableMap.Builder<String, Method> builder = ImmutableMap.builder(); 374 for (Method method : TypeVariableImpl.class.getMethods()) { 375 if (method.getDeclaringClass().equals(TypeVariableImpl.class)) { 376 try { 377 method.setAccessible(true); 378 } catch (AccessControlException e) { 379 // OK: the method is accessible to us anyway. The setAccessible call is only for 380 // unusual execution environments where that might not be true. 381 } 382 builder.put(method.getName(), method); 383 } 384 } 385 typeVariableMethods = builder.build(); 386 } 387 388 private final TypeVariableImpl<?> typeVariableImpl; 389 390 TypeVariableInvocationHandler(TypeVariableImpl<?> typeVariableImpl) { 391 this.typeVariableImpl = typeVariableImpl; 392 } 393 394 @Override 395 @CheckForNull 396 public Object invoke(Object proxy, Method method, @CheckForNull @Nullable Object[] args) 397 throws Throwable { 398 String methodName = method.getName(); 399 Method typeVariableMethod = typeVariableMethods.get(methodName); 400 if (typeVariableMethod == null) { 401 throw new UnsupportedOperationException(methodName); 402 } else { 403 try { 404 return typeVariableMethod.invoke(typeVariableImpl, args); 405 } catch (InvocationTargetException e) { 406 throw e.getCause(); 407 } 408 } 409 } 410 } 411 412 private static final class TypeVariableImpl<D extends GenericDeclaration> { 413 414 private final D genericDeclaration; 415 private final String name; 416 private final ImmutableList<Type> bounds; 417 418 TypeVariableImpl(D genericDeclaration, String name, Type[] bounds) { 419 disallowPrimitiveType(bounds, "bound for type variable"); 420 this.genericDeclaration = checkNotNull(genericDeclaration); 421 this.name = checkNotNull(name); 422 this.bounds = ImmutableList.copyOf(bounds); 423 } 424 425 public Type[] getBounds() { 426 return toArray(bounds); 427 } 428 429 public D getGenericDeclaration() { 430 return genericDeclaration; 431 } 432 433 public String getName() { 434 return name; 435 } 436 437 public String getTypeName() { 438 return name; 439 } 440 441 @Override 442 public String toString() { 443 return name; 444 } 445 446 @Override 447 public int hashCode() { 448 return genericDeclaration.hashCode() ^ name.hashCode(); 449 } 450 451 @Override 452 public boolean equals(@CheckForNull Object obj) { 453 if (NativeTypeVariableEquals.NATIVE_TYPE_VARIABLE_ONLY) { 454 // equal only to our TypeVariable implementation with identical bounds 455 if (obj != null 456 && Proxy.isProxyClass(obj.getClass()) 457 && Proxy.getInvocationHandler(obj) instanceof TypeVariableInvocationHandler) { 458 TypeVariableInvocationHandler typeVariableInvocationHandler = 459 (TypeVariableInvocationHandler) Proxy.getInvocationHandler(obj); 460 TypeVariableImpl<?> that = typeVariableInvocationHandler.typeVariableImpl; 461 return name.equals(that.getName()) 462 && genericDeclaration.equals(that.getGenericDeclaration()) 463 && bounds.equals(that.bounds); 464 } 465 return false; 466 } else { 467 // equal to any TypeVariable implementation regardless of bounds 468 if (obj instanceof TypeVariable) { 469 TypeVariable<?> that = (TypeVariable<?>) obj; 470 return name.equals(that.getName()) 471 && genericDeclaration.equals(that.getGenericDeclaration()); 472 } 473 return false; 474 } 475 } 476 } 477 478 static final class WildcardTypeImpl implements WildcardType, Serializable { 479 480 private final ImmutableList<Type> lowerBounds; 481 private final ImmutableList<Type> upperBounds; 482 483 WildcardTypeImpl(Type[] lowerBounds, Type[] upperBounds) { 484 disallowPrimitiveType(lowerBounds, "lower bound for wildcard"); 485 disallowPrimitiveType(upperBounds, "upper bound for wildcard"); 486 this.lowerBounds = JavaVersion.CURRENT.usedInGenericType(lowerBounds); 487 this.upperBounds = JavaVersion.CURRENT.usedInGenericType(upperBounds); 488 } 489 490 @Override 491 public Type[] getLowerBounds() { 492 return toArray(lowerBounds); 493 } 494 495 @Override 496 public Type[] getUpperBounds() { 497 return toArray(upperBounds); 498 } 499 500 @Override 501 public boolean equals(@CheckForNull Object obj) { 502 if (obj instanceof WildcardType) { 503 WildcardType that = (WildcardType) obj; 504 return lowerBounds.equals(Arrays.asList(that.getLowerBounds())) 505 && upperBounds.equals(Arrays.asList(that.getUpperBounds())); 506 } 507 return false; 508 } 509 510 @Override 511 public int hashCode() { 512 return lowerBounds.hashCode() ^ upperBounds.hashCode(); 513 } 514 515 @Override 516 public String toString() { 517 StringBuilder builder = new StringBuilder("?"); 518 for (Type lowerBound : lowerBounds) { 519 builder.append(" super ").append(JavaVersion.CURRENT.typeName(lowerBound)); 520 } 521 for (Type upperBound : filterUpperBounds(upperBounds)) { 522 builder.append(" extends ").append(JavaVersion.CURRENT.typeName(upperBound)); 523 } 524 return builder.toString(); 525 } 526 527 private static final long serialVersionUID = 0; 528 } 529 530 private static Type[] toArray(Collection<Type> types) { 531 return types.toArray(new Type[0]); 532 } 533 534 private static Iterable<Type> filterUpperBounds(Iterable<Type> bounds) { 535 return Iterables.filter(bounds, Predicates.not(Predicates.<Type>equalTo(Object.class))); 536 } 537 538 private static void disallowPrimitiveType(Type[] types, String usedAs) { 539 for (Type type : types) { 540 if (type instanceof Class) { 541 Class<?> cls = (Class<?>) type; 542 checkArgument(!cls.isPrimitive(), "Primitive type '%s' used as %s", cls, usedAs); 543 } 544 } 545 } 546 547 /** Returns the {@code Class} object of arrays with {@code componentType}. */ 548 static Class<?> getArrayClass(Class<?> componentType) { 549 // TODO(user): This is not the most efficient way to handle generic 550 // arrays, but is there another way to extract the array class in a 551 // non-hacky way (i.e. using String value class names- "[L...")? 552 return Array.newInstance(componentType, 0).getClass(); 553 } 554 555 // TODO(benyu): Once behavior is the same for all Java versions we support, delete this. 556 enum JavaVersion { 557 JAVA6 { 558 @Override 559 GenericArrayType newArrayType(Type componentType) { 560 return new GenericArrayTypeImpl(componentType); 561 } 562 563 @Override 564 Type usedInGenericType(Type type) { 565 checkNotNull(type); 566 if (type instanceof Class) { 567 Class<?> cls = (Class<?>) type; 568 if (cls.isArray()) { 569 return new GenericArrayTypeImpl(cls.getComponentType()); 570 } 571 } 572 return type; 573 } 574 }, 575 JAVA7 { 576 @Override 577 Type newArrayType(Type componentType) { 578 if (componentType instanceof Class) { 579 return getArrayClass((Class<?>) componentType); 580 } else { 581 return new GenericArrayTypeImpl(componentType); 582 } 583 } 584 585 @Override 586 Type usedInGenericType(Type type) { 587 return checkNotNull(type); 588 } 589 }, 590 JAVA8 { 591 @Override 592 Type newArrayType(Type componentType) { 593 return JAVA7.newArrayType(componentType); 594 } 595 596 @Override 597 Type usedInGenericType(Type type) { 598 return JAVA7.usedInGenericType(type); 599 } 600 601 @Override 602 String typeName(Type type) { 603 try { 604 Method getTypeName = Type.class.getMethod("getTypeName"); 605 return (String) getTypeName.invoke(type); 606 } catch (NoSuchMethodException e) { 607 throw new AssertionError("Type.getTypeName should be available in Java 8"); 608 /* 609 * Do not merge the 2 catch blocks below. javac would infer a type of 610 * ReflectiveOperationException, which Animal Sniffer would reject. (Old versions of 611 * Android don't *seem* to mind, but there might be edge cases of which we're unaware.) 612 */ 613 } catch (InvocationTargetException e) { 614 throw new RuntimeException(e); 615 } catch (IllegalAccessException e) { 616 throw new RuntimeException(e); 617 } 618 } 619 }, 620 JAVA9 { 621 @Override 622 Type newArrayType(Type componentType) { 623 return JAVA8.newArrayType(componentType); 624 } 625 626 @Override 627 Type usedInGenericType(Type type) { 628 return JAVA8.usedInGenericType(type); 629 } 630 631 @Override 632 String typeName(Type type) { 633 return JAVA8.typeName(type); 634 } 635 636 @Override 637 boolean jdkTypeDuplicatesOwnerName() { 638 return false; 639 } 640 }; 641 642 static final JavaVersion CURRENT; 643 644 static { 645 if (AnnotatedElement.class.isAssignableFrom(TypeVariable.class)) { 646 if (new TypeCapture<Entry<String, int[][]>>() {}.capture() 647 .toString() 648 .contains("java.util.Map.java.util.Map")) { 649 CURRENT = JAVA8; 650 } else { 651 CURRENT = JAVA9; 652 } 653 } else if (new TypeCapture<int[]>() {}.capture() instanceof Class) { 654 CURRENT = JAVA7; 655 } else { 656 CURRENT = JAVA6; 657 } 658 } 659 660 abstract Type newArrayType(Type componentType); 661 662 abstract Type usedInGenericType(Type type); 663 664 final ImmutableList<Type> usedInGenericType(Type[] types) { 665 ImmutableList.Builder<Type> builder = ImmutableList.builder(); 666 for (Type type : types) { 667 builder.add(usedInGenericType(type)); 668 } 669 return builder.build(); 670 } 671 672 String typeName(Type type) { 673 return Types.toString(type); 674 } 675 676 boolean jdkTypeDuplicatesOwnerName() { 677 return true; 678 } 679 } 680 681 /** 682 * Per <a href="https://code.google.com/p/guava-libraries/issues/detail?id=1635">issue 1635</a>, 683 * In JDK 1.7.0_51-b13, {@link TypeVariableImpl#equals(Object)} is changed to no longer be equal 684 * to custom TypeVariable implementations. As a result, we need to make sure our TypeVariable 685 * implementation respects symmetry. Moreover, we don't want to reconstruct a native type variable 686 * {@code <A>} using our implementation unless some of its bounds have changed in resolution. This 687 * avoids creating unequal TypeVariable implementation unnecessarily. When the bounds do change, 688 * however, it's fine for the synthetic TypeVariable to be unequal to any native TypeVariable 689 * anyway. 690 */ 691 static final class NativeTypeVariableEquals<X> { 692 static final boolean NATIVE_TYPE_VARIABLE_ONLY = 693 !NativeTypeVariableEquals.class.getTypeParameters()[0].equals( 694 newArtificialTypeVariable(NativeTypeVariableEquals.class, "X")); 695 } 696 697 private Types() {} 698 }