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 }