1 /* 2 * Copyright (C) 2008 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.inject.internal; 18 19 import static com.google.common.base.Preconditions.checkArgument; 20 import static com.google.common.base.Preconditions.checkNotNull; 21 22 import com.google.common.base.Objects; 23 import com.google.common.collect.ImmutableMap; 24 import com.google.inject.ConfigurationException; 25 import com.google.inject.Key; 26 import com.google.inject.TypeLiteral; 27 import com.google.inject.util.Types; 28 import java.io.Serializable; 29 import java.lang.reflect.Array; 30 import java.lang.reflect.GenericArrayType; 31 import java.lang.reflect.GenericDeclaration; 32 import java.lang.reflect.ParameterizedType; 33 import java.lang.reflect.Type; 34 import java.lang.reflect.TypeVariable; 35 import java.lang.reflect.WildcardType; 36 import java.util.Arrays; 37 import java.util.NoSuchElementException; 38 39 /** 40 * Static methods for working with types that we aren't publishing in the public {@code Types} API. 41 * 42 * @author jessewilson@google.com (Jesse Wilson) 43 */ 44 public class MoreTypes { 45 46 public static final Type[] EMPTY_TYPE_ARRAY = new Type[] {}; 47 MoreTypes()48 private MoreTypes() {} 49 50 private static final ImmutableMap<TypeLiteral<?>, TypeLiteral<?>> PRIMITIVE_TO_WRAPPER = 51 new ImmutableMap.Builder<TypeLiteral<?>, TypeLiteral<?>>() 52 .put(TypeLiteral.get(boolean.class), TypeLiteral.get(Boolean.class)) 53 .put(TypeLiteral.get(byte.class), TypeLiteral.get(Byte.class)) 54 .put(TypeLiteral.get(short.class), TypeLiteral.get(Short.class)) 55 .put(TypeLiteral.get(int.class), TypeLiteral.get(Integer.class)) 56 .put(TypeLiteral.get(long.class), TypeLiteral.get(Long.class)) 57 .put(TypeLiteral.get(float.class), TypeLiteral.get(Float.class)) 58 .put(TypeLiteral.get(double.class), TypeLiteral.get(Double.class)) 59 .put(TypeLiteral.get(char.class), TypeLiteral.get(Character.class)) 60 .put(TypeLiteral.get(void.class), TypeLiteral.get(Void.class)) 61 .build(); 62 63 /** 64 * Returns a key that doesn't hold any references to parent classes. This is necessary for 65 * anonymous keys, so ensure we don't hold a ref to the containing module (or class) forever. 66 */ canonicalizeKey(Key<T> key)67 public static <T> Key<T> canonicalizeKey(Key<T> key) { 68 // If we know this isn't a subclass, return as-is. 69 // Otherwise, recreate the key to avoid the subclass 70 if (key.getClass() == Key.class) { 71 return key; 72 } else if (key.getAnnotation() != null) { 73 return Key.get(key.getTypeLiteral(), key.getAnnotation()); 74 } else if (key.getAnnotationType() != null) { 75 return Key.get(key.getTypeLiteral(), key.getAnnotationType()); 76 } else { 77 return Key.get(key.getTypeLiteral()); 78 } 79 } 80 81 /** 82 * Returns an type that's appropriate for use in a key. 83 * 84 * <p>If the raw type of {@code typeLiteral} is a {@code javax.inject.Provider}, this returns a 85 * {@code com.google.inject.Provider} with the same type parameters. 86 * 87 * <p>If the type is a primitive, the corresponding wrapper type will be returned. 88 * 89 * @throws ConfigurationException if {@code type} contains a type variable 90 */ canonicalizeForKey(TypeLiteral<T> typeLiteral)91 public static <T> TypeLiteral<T> canonicalizeForKey(TypeLiteral<T> typeLiteral) { 92 Type type = typeLiteral.getType(); 93 if (!isFullySpecified(type)) { 94 Errors errors = new Errors().keyNotFullySpecified(typeLiteral); 95 throw new ConfigurationException(errors.getMessages()); 96 } 97 98 if (typeLiteral.getRawType() == javax.inject.Provider.class) { 99 ParameterizedType parameterizedType = (ParameterizedType) type; 100 101 // the following casts are generally unsafe, but com.google.inject.Provider extends 102 // javax.inject.Provider and is covariant 103 @SuppressWarnings("unchecked") 104 TypeLiteral<T> guiceProviderType = 105 (TypeLiteral<T>) 106 TypeLiteral.get(Types.providerOf(parameterizedType.getActualTypeArguments()[0])); 107 return guiceProviderType; 108 } 109 110 @SuppressWarnings("unchecked") 111 TypeLiteral<T> wrappedPrimitives = (TypeLiteral<T>) PRIMITIVE_TO_WRAPPER.get(typeLiteral); 112 if (wrappedPrimitives != null) { 113 return wrappedPrimitives; 114 } 115 116 // If we know this isn't a subclass, return as-is. 117 if (typeLiteral.getClass() == TypeLiteral.class) { 118 return typeLiteral; 119 } 120 121 // recreate the TypeLiteral to avoid anonymous TypeLiterals from holding refs to their 122 // surrounding classes. 123 @SuppressWarnings("unchecked") 124 TypeLiteral<T> recreated = (TypeLiteral<T>) TypeLiteral.get(typeLiteral.getType()); 125 return recreated; 126 } 127 128 /** Returns true if {@code type} is free from type variables. */ isFullySpecified(Type type)129 private static boolean isFullySpecified(Type type) { 130 if (type instanceof Class) { 131 return true; 132 133 } else if (type instanceof CompositeType) { 134 return ((CompositeType) type).isFullySpecified(); 135 136 } else if (type instanceof TypeVariable) { 137 return false; 138 139 } else { 140 return ((CompositeType) canonicalize(type)).isFullySpecified(); 141 } 142 } 143 144 /** 145 * Returns a type that is functionally equal but not necessarily equal according to {@link 146 * Object#equals(Object) Object.equals()}. The returned type is {@link Serializable}. 147 */ canonicalize(Type type)148 public static Type canonicalize(Type type) { 149 if (type instanceof Class) { 150 Class<?> c = (Class<?>) type; 151 return c.isArray() ? new GenericArrayTypeImpl(canonicalize(c.getComponentType())) : c; 152 153 } else if (type instanceof CompositeType) { 154 return type; 155 156 } else if (type instanceof ParameterizedType) { 157 ParameterizedType p = (ParameterizedType) type; 158 return new ParameterizedTypeImpl( 159 p.getOwnerType(), p.getRawType(), p.getActualTypeArguments()); 160 161 } else if (type instanceof GenericArrayType) { 162 GenericArrayType g = (GenericArrayType) type; 163 return new GenericArrayTypeImpl(g.getGenericComponentType()); 164 165 } else if (type instanceof WildcardType) { 166 WildcardType w = (WildcardType) type; 167 return new WildcardTypeImpl(w.getUpperBounds(), w.getLowerBounds()); 168 169 } else { 170 // type is either serializable as-is or unsupported 171 return type; 172 } 173 } 174 getRawType(Type type)175 public static Class<?> getRawType(Type type) { 176 if (type instanceof Class<?>) { 177 // type is a normal class. 178 return (Class<?>) type; 179 180 } else if (type instanceof ParameterizedType) { 181 ParameterizedType parameterizedType = (ParameterizedType) type; 182 183 // I'm not exactly sure why getRawType() returns Type instead of Class. 184 // Neal isn't either but suspects some pathological case related 185 // to nested classes exists. 186 Type rawType = parameterizedType.getRawType(); 187 checkArgument( 188 rawType instanceof Class, 189 "Expected a Class, but <%s> is of type %s", 190 type, 191 type.getClass().getName()); 192 return (Class<?>) rawType; 193 194 } else if (type instanceof GenericArrayType) { 195 Type componentType = ((GenericArrayType) type).getGenericComponentType(); 196 return Array.newInstance(getRawType(componentType), 0).getClass(); 197 198 } else if (type instanceof TypeVariable || type instanceof WildcardType) { 199 // we could use the variable's bounds, but that'll won't work if there are multiple. 200 // having a raw type that's more general than necessary is okay 201 return Object.class; 202 203 } else { 204 throw new IllegalArgumentException( 205 "Expected a Class, ParameterizedType, or " 206 + "GenericArrayType, but <" 207 + type 208 + "> is of type " 209 + type.getClass().getName()); 210 } 211 } 212 213 /** Returns true if {@code a} and {@code b} are equal. */ equals(Type a, Type b)214 public static boolean equals(Type a, Type b) { 215 if (a == b) { 216 // also handles (a == null && b == null) 217 return true; 218 219 } else if (a instanceof Class) { 220 // Class already specifies equals(). 221 return a.equals(b); 222 223 } else if (a instanceof ParameterizedType) { 224 if (!(b instanceof ParameterizedType)) { 225 return false; 226 } 227 228 // TODO: save a .clone() call 229 ParameterizedType pa = (ParameterizedType) a; 230 ParameterizedType pb = (ParameterizedType) b; 231 return Objects.equal(pa.getOwnerType(), pb.getOwnerType()) 232 && pa.getRawType().equals(pb.getRawType()) 233 && Arrays.equals(pa.getActualTypeArguments(), pb.getActualTypeArguments()); 234 235 } else if (a instanceof GenericArrayType) { 236 if (!(b instanceof GenericArrayType)) { 237 return false; 238 } 239 240 GenericArrayType ga = (GenericArrayType) a; 241 GenericArrayType gb = (GenericArrayType) b; 242 return equals(ga.getGenericComponentType(), gb.getGenericComponentType()); 243 244 } else if (a instanceof WildcardType) { 245 if (!(b instanceof WildcardType)) { 246 return false; 247 } 248 249 WildcardType wa = (WildcardType) a; 250 WildcardType wb = (WildcardType) b; 251 return Arrays.equals(wa.getUpperBounds(), wb.getUpperBounds()) 252 && Arrays.equals(wa.getLowerBounds(), wb.getLowerBounds()); 253 254 } else if (a instanceof TypeVariable) { 255 if (!(b instanceof TypeVariable)) { 256 return false; 257 } 258 TypeVariable<?> va = (TypeVariable) a; 259 TypeVariable<?> vb = (TypeVariable) b; 260 return va.getGenericDeclaration().equals(vb.getGenericDeclaration()) 261 && va.getName().equals(vb.getName()); 262 263 } else { 264 // This isn't a type we support. Could be a generic array type, wildcard type, etc. 265 return false; 266 } 267 } 268 hashCodeOrZero(Object o)269 private static int hashCodeOrZero(Object o) { 270 return o != null ? o.hashCode() : 0; 271 } 272 typeToString(Type type)273 public static String typeToString(Type type) { 274 return type instanceof Class ? ((Class) type).getName() : type.toString(); 275 } 276 277 /** 278 * Returns the generic supertype for {@code type}. For example, given a class {@code IntegerSet}, 279 * the result for when supertype is {@code Set.class} is {@code Set<Integer>} and the result when 280 * the supertype is {@code Collection.class} is {@code Collection<Integer>}. 281 */ getGenericSupertype(Type type, Class<?> rawType, Class<?> toResolve)282 public static Type getGenericSupertype(Type type, Class<?> rawType, Class<?> toResolve) { 283 if (toResolve == rawType) { 284 return type; 285 } 286 287 // we skip searching through interfaces if unknown is an interface 288 if (toResolve.isInterface()) { 289 Class[] interfaces = rawType.getInterfaces(); 290 for (int i = 0, length = interfaces.length; i < length; i++) { 291 if (interfaces[i] == toResolve) { 292 return rawType.getGenericInterfaces()[i]; 293 } else if (toResolve.isAssignableFrom(interfaces[i])) { 294 return getGenericSupertype(rawType.getGenericInterfaces()[i], interfaces[i], toResolve); 295 } 296 } 297 } 298 299 // check our supertypes 300 if (!rawType.isInterface()) { 301 while (rawType != Object.class) { 302 Class<?> rawSupertype = rawType.getSuperclass(); 303 if (rawSupertype == toResolve) { 304 return rawType.getGenericSuperclass(); 305 } else if (toResolve.isAssignableFrom(rawSupertype)) { 306 return getGenericSupertype(rawType.getGenericSuperclass(), rawSupertype, toResolve); 307 } 308 rawType = rawSupertype; 309 } 310 } 311 312 // we can't resolve this further 313 return toResolve; 314 } 315 resolveTypeVariable(Type type, Class<?> rawType, TypeVariable unknown)316 public static Type resolveTypeVariable(Type type, Class<?> rawType, TypeVariable unknown) { 317 Class<?> declaredByRaw = declaringClassOf(unknown); 318 319 // we can't reduce this further 320 if (declaredByRaw == null) { 321 return unknown; 322 } 323 324 Type declaredBy = getGenericSupertype(type, rawType, declaredByRaw); 325 if (declaredBy instanceof ParameterizedType) { 326 int index = indexOf(declaredByRaw.getTypeParameters(), unknown); 327 return ((ParameterizedType) declaredBy).getActualTypeArguments()[index]; 328 } 329 330 return unknown; 331 } 332 indexOf(Object[] array, Object toFind)333 private static int indexOf(Object[] array, Object toFind) { 334 for (int i = 0; i < array.length; i++) { 335 if (toFind.equals(array[i])) { 336 return i; 337 } 338 } 339 throw new NoSuchElementException(); 340 } 341 342 /** 343 * Returns the declaring class of {@code typeVariable}, or {@code null} if it was not declared by 344 * a class. 345 */ declaringClassOf(TypeVariable typeVariable)346 private static Class<?> declaringClassOf(TypeVariable typeVariable) { 347 GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration(); 348 return genericDeclaration instanceof Class ? (Class<?>) genericDeclaration : null; 349 } 350 351 public static class ParameterizedTypeImpl 352 implements ParameterizedType, Serializable, CompositeType { 353 private final Type ownerType; 354 private final Type rawType; 355 private final Type[] typeArguments; 356 ParameterizedTypeImpl(Type ownerType, Type rawType, Type... typeArguments)357 public ParameterizedTypeImpl(Type ownerType, Type rawType, Type... typeArguments) { 358 // require an owner type if the raw type needs it 359 ensureOwnerType(ownerType, rawType); 360 361 this.ownerType = ownerType == null ? null : canonicalize(ownerType); 362 this.rawType = canonicalize(rawType); 363 this.typeArguments = typeArguments.clone(); 364 for (int t = 0; t < this.typeArguments.length; t++) { 365 checkNotNull(this.typeArguments[t], "type parameter"); 366 checkNotPrimitive(this.typeArguments[t], "type parameters"); 367 this.typeArguments[t] = canonicalize(this.typeArguments[t]); 368 } 369 } 370 371 @Override getActualTypeArguments()372 public Type[] getActualTypeArguments() { 373 return typeArguments.clone(); 374 } 375 376 @Override getRawType()377 public Type getRawType() { 378 return rawType; 379 } 380 381 @Override getOwnerType()382 public Type getOwnerType() { 383 return ownerType; 384 } 385 386 @Override isFullySpecified()387 public boolean isFullySpecified() { 388 if (ownerType != null && !MoreTypes.isFullySpecified(ownerType)) { 389 return false; 390 } 391 392 if (!MoreTypes.isFullySpecified(rawType)) { 393 return false; 394 } 395 396 for (Type type : typeArguments) { 397 if (!MoreTypes.isFullySpecified(type)) { 398 return false; 399 } 400 } 401 402 return true; 403 } 404 405 @Override equals(Object other)406 public boolean equals(Object other) { 407 return other instanceof ParameterizedType 408 && MoreTypes.equals(this, (ParameterizedType) other); 409 } 410 411 @Override hashCode()412 public int hashCode() { 413 return Arrays.hashCode(typeArguments) ^ rawType.hashCode() ^ hashCodeOrZero(ownerType); 414 } 415 416 @Override toString()417 public String toString() { 418 StringBuilder stringBuilder = new StringBuilder(30 * (typeArguments.length + 1)); 419 stringBuilder.append(typeToString(rawType)); 420 421 if (typeArguments.length == 0) { 422 return stringBuilder.toString(); 423 } 424 425 stringBuilder.append("<").append(typeToString(typeArguments[0])); 426 for (int i = 1; i < typeArguments.length; i++) { 427 stringBuilder.append(", ").append(typeToString(typeArguments[i])); 428 } 429 return stringBuilder.append(">").toString(); 430 } 431 ensureOwnerType(Type ownerType, Type rawType)432 private static void ensureOwnerType(Type ownerType, Type rawType) { 433 if (rawType instanceof Class<?>) { 434 Class rawTypeAsClass = (Class) rawType; 435 checkArgument( 436 ownerType != null || rawTypeAsClass.getEnclosingClass() == null, 437 "No owner type for enclosed %s", 438 rawType); 439 checkArgument( 440 ownerType == null || rawTypeAsClass.getEnclosingClass() != null, 441 "Owner type for unenclosed %s", 442 rawType); 443 } 444 } 445 446 private static final long serialVersionUID = 0; 447 } 448 449 public static class GenericArrayTypeImpl 450 implements GenericArrayType, Serializable, CompositeType { 451 private final Type componentType; 452 GenericArrayTypeImpl(Type componentType)453 public GenericArrayTypeImpl(Type componentType) { 454 this.componentType = canonicalize(componentType); 455 } 456 457 @Override getGenericComponentType()458 public Type getGenericComponentType() { 459 return componentType; 460 } 461 462 @Override isFullySpecified()463 public boolean isFullySpecified() { 464 return MoreTypes.isFullySpecified(componentType); 465 } 466 467 @Override equals(Object o)468 public boolean equals(Object o) { 469 return o instanceof GenericArrayType && MoreTypes.equals(this, (GenericArrayType) o); 470 } 471 472 @Override hashCode()473 public int hashCode() { 474 return componentType.hashCode(); 475 } 476 477 @Override toString()478 public String toString() { 479 return typeToString(componentType) + "[]"; 480 } 481 482 private static final long serialVersionUID = 0; 483 } 484 485 /** 486 * The WildcardType interface supports multiple upper bounds and multiple lower bounds. We only 487 * support what the Java 6 language needs - at most one bound. If a lower bound is set, the upper 488 * bound must be Object.class. 489 */ 490 public static class WildcardTypeImpl implements WildcardType, Serializable, CompositeType { 491 private final Type upperBound; 492 private final Type lowerBound; 493 WildcardTypeImpl(Type[] upperBounds, Type[] lowerBounds)494 public WildcardTypeImpl(Type[] upperBounds, Type[] lowerBounds) { 495 checkArgument(lowerBounds.length <= 1, "Must have at most one lower bound."); 496 checkArgument(upperBounds.length == 1, "Must have exactly one upper bound."); 497 498 if (lowerBounds.length == 1) { 499 checkNotNull(lowerBounds[0], "lowerBound"); 500 checkNotPrimitive(lowerBounds[0], "wildcard bounds"); 501 checkArgument(upperBounds[0] == Object.class, "bounded both ways"); 502 this.lowerBound = canonicalize(lowerBounds[0]); 503 this.upperBound = Object.class; 504 505 } else { 506 checkNotNull(upperBounds[0], "upperBound"); 507 checkNotPrimitive(upperBounds[0], "wildcard bounds"); 508 this.lowerBound = null; 509 this.upperBound = canonicalize(upperBounds[0]); 510 } 511 } 512 513 @Override getUpperBounds()514 public Type[] getUpperBounds() { 515 return new Type[] {upperBound}; 516 } 517 518 @Override getLowerBounds()519 public Type[] getLowerBounds() { 520 return lowerBound != null ? new Type[] {lowerBound} : EMPTY_TYPE_ARRAY; 521 } 522 523 @Override isFullySpecified()524 public boolean isFullySpecified() { 525 return MoreTypes.isFullySpecified(upperBound) 526 && (lowerBound == null || MoreTypes.isFullySpecified(lowerBound)); 527 } 528 529 @Override equals(Object other)530 public boolean equals(Object other) { 531 return other instanceof WildcardType && MoreTypes.equals(this, (WildcardType) other); 532 } 533 534 @Override hashCode()535 public int hashCode() { 536 // this equals Arrays.hashCode(getLowerBounds()) ^ Arrays.hashCode(getUpperBounds()); 537 return (lowerBound != null ? 31 + lowerBound.hashCode() : 1) ^ (31 + upperBound.hashCode()); 538 } 539 540 @Override toString()541 public String toString() { 542 if (lowerBound != null) { 543 return "? super " + typeToString(lowerBound); 544 } else if (upperBound == Object.class) { 545 return "?"; 546 } else { 547 return "? extends " + typeToString(upperBound); 548 } 549 } 550 551 private static final long serialVersionUID = 0; 552 } 553 checkNotPrimitive(Type type, String use)554 private static void checkNotPrimitive(Type type, String use) { 555 checkArgument( 556 !(type instanceof Class<?>) || !((Class) type).isPrimitive(), 557 "Primitive types are not allowed in %s: %s", 558 use, 559 type); 560 } 561 562 /** A type formed from other types, such as arrays, parameterized types or wildcard types */ 563 private interface CompositeType { 564 /** Returns true if there are no type variables in this type. */ isFullySpecified()565 boolean isFullySpecified(); 566 } 567 } 568