1 /** 2 * Copyright (C) 2006 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; 18 19 import static com.google.common.base.Preconditions.checkArgument; 20 import static com.google.common.base.Preconditions.checkNotNull; 21 import static com.google.inject.internal.Annotations.generateAnnotation; 22 import static com.google.inject.internal.Annotations.isAllDefaultMethods; 23 24 import com.google.common.base.Supplier; 25 import com.google.common.base.Suppliers; 26 import com.google.inject.internal.Annotations; 27 import com.google.inject.internal.MoreTypes; 28 29 import java.lang.annotation.Annotation; 30 import java.lang.reflect.Type; 31 32 /** 33 * Binding key consisting of an injection type and an optional annotation. 34 * Matches the type and annotation at a point of injection. 35 * 36 * <p>For example, {@code Key.get(Service.class, Transactional.class)} will 37 * match: 38 * 39 * <pre> 40 * {@literal @}Inject 41 * public void setService({@literal @}Transactional Service service) { 42 * ... 43 * } 44 * </pre> 45 * 46 * <p>{@code Key} supports generic types via subclassing just like {@link 47 * TypeLiteral}. 48 * 49 * <p>Keys do not differentiate between primitive types (int, char, etc.) and 50 * their corresponding wrapper types (Integer, Character, etc.). Primitive 51 * types will be replaced with their wrapper types when keys are created. 52 * 53 * @author crazybob@google.com (Bob Lee) 54 */ 55 public class Key<T> { 56 57 private final AnnotationStrategy annotationStrategy; 58 59 private final TypeLiteral<T> typeLiteral; 60 private final int hashCode; 61 private final Supplier<String> toStringSupplier; 62 63 /** 64 * Constructs a new key. Derives the type from this class's type parameter. 65 * 66 * <p>Clients create an empty anonymous subclass. Doing so embeds the type 67 * parameter in the anonymous class's type hierarchy so we can reconstitute it 68 * at runtime despite erasure. 69 * 70 * <p>Example usage for a binding of type {@code Foo} annotated with 71 * {@code @Bar}: 72 * 73 * <p>{@code new Key<Foo>(Bar.class) {}}. 74 */ 75 @SuppressWarnings("unchecked") Key(Class<? extends Annotation> annotationType)76 protected Key(Class<? extends Annotation> annotationType) { 77 this.annotationStrategy = strategyFor(annotationType); 78 this.typeLiteral = MoreTypes.canonicalizeForKey( 79 (TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass())); 80 this.hashCode = computeHashCode(); 81 this.toStringSupplier = createToStringSupplier(); 82 } 83 84 /** 85 * Constructs a new key. Derives the type from this class's type parameter. 86 * 87 * <p>Clients create an empty anonymous subclass. Doing so embeds the type 88 * parameter in the anonymous class's type hierarchy so we can reconstitute it 89 * at runtime despite erasure. 90 * 91 * <p>Example usage for a binding of type {@code Foo} annotated with 92 * {@code @Bar}: 93 * 94 * <p>{@code new Key<Foo>(new Bar()) {}}. 95 */ 96 @SuppressWarnings("unchecked") Key(Annotation annotation)97 protected Key(Annotation annotation) { 98 // no usages, not test-covered 99 this.annotationStrategy = strategyFor(annotation); 100 this.typeLiteral = MoreTypes.canonicalizeForKey( 101 (TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass())); 102 this.hashCode = computeHashCode(); 103 this.toStringSupplier = createToStringSupplier(); 104 } 105 106 /** 107 * Constructs a new key. Derives the type from this class's type parameter. 108 * 109 * <p>Clients create an empty anonymous subclass. Doing so embeds the type 110 * parameter in the anonymous class's type hierarchy so we can reconstitute it 111 * at runtime despite erasure. 112 * 113 * <p>Example usage for a binding of type {@code Foo}: 114 * 115 * <p>{@code new Key<Foo>() {}}. 116 */ 117 @SuppressWarnings("unchecked") Key()118 protected Key() { 119 this.annotationStrategy = NullAnnotationStrategy.INSTANCE; 120 this.typeLiteral = MoreTypes.canonicalizeForKey( 121 (TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass())); 122 this.hashCode = computeHashCode(); 123 this.toStringSupplier = createToStringSupplier(); 124 } 125 126 /** 127 * Unsafe. Constructs a key from a manually specified type. 128 */ 129 @SuppressWarnings("unchecked") Key(Type type, AnnotationStrategy annotationStrategy)130 private Key(Type type, AnnotationStrategy annotationStrategy) { 131 this.annotationStrategy = annotationStrategy; 132 this.typeLiteral = MoreTypes.canonicalizeForKey((TypeLiteral<T>) TypeLiteral.get(type)); 133 this.hashCode = computeHashCode(); 134 this.toStringSupplier = createToStringSupplier(); 135 } 136 137 /** Constructs a key from a manually specified type. */ Key(TypeLiteral<T> typeLiteral, AnnotationStrategy annotationStrategy)138 private Key(TypeLiteral<T> typeLiteral, AnnotationStrategy annotationStrategy) { 139 this.annotationStrategy = annotationStrategy; 140 this.typeLiteral = MoreTypes.canonicalizeForKey(typeLiteral); 141 this.hashCode = computeHashCode(); 142 this.toStringSupplier = createToStringSupplier(); 143 } 144 145 /** 146 * Computes the hash code for this key. 147 */ computeHashCode()148 private int computeHashCode() { 149 return typeLiteral.hashCode() * 31 + annotationStrategy.hashCode(); 150 } 151 152 /** 153 * @return a {@link Supplier} which memoizes the value for lazy initialization. 154 */ createToStringSupplier()155 private Supplier<String> createToStringSupplier() { 156 // The performance hit on access is acceptable since the intended use is for non-performance- 157 // critical applications such as debugging and logging. 158 return Suppliers.memoize(new Supplier<String>() { 159 @Override public String get() { 160 return "Key[type=" + typeLiteral + ", annotation=" + annotationStrategy + "]"; 161 } 162 }); 163 } 164 165 /** 166 * Gets the key type. 167 */ 168 public final TypeLiteral<T> getTypeLiteral() { 169 return typeLiteral; 170 } 171 172 /** 173 * Gets the annotation type. 174 */ 175 public final Class<? extends Annotation> getAnnotationType() { 176 return annotationStrategy.getAnnotationType(); 177 } 178 179 /** 180 * Gets the annotation. 181 */ 182 public final Annotation getAnnotation() { 183 return annotationStrategy.getAnnotation(); 184 } 185 186 boolean hasAnnotationType() { 187 return annotationStrategy.getAnnotationType() != null; 188 } 189 190 String getAnnotationName() { 191 Annotation annotation = annotationStrategy.getAnnotation(); 192 if (annotation != null) { 193 return annotation.toString(); 194 } 195 196 // not test-covered 197 return annotationStrategy.getAnnotationType().toString(); 198 } 199 200 Class<? super T> getRawType() { 201 return typeLiteral.getRawType(); 202 } 203 204 /** 205 * Gets the key of this key's provider. 206 */ 207 Key<Provider<T>> providerKey() { 208 return ofType(typeLiteral.providerType()); 209 } 210 211 @Override public final boolean equals(Object o) { 212 if (o == this) { 213 return true; 214 } 215 if (!(o instanceof Key<?>)) { 216 return false; 217 } 218 Key<?> other = (Key<?>) o; 219 return annotationStrategy.equals(other.annotationStrategy) 220 && typeLiteral.equals(other.typeLiteral); 221 } 222 223 @Override public final int hashCode() { 224 return this.hashCode; 225 } 226 227 @Override public final String toString() { 228 return toStringSupplier.get(); 229 } 230 231 /** 232 * Gets a key for an injection type and an annotation strategy. 233 */ 234 static <T> Key<T> get(Class<T> type, 235 AnnotationStrategy annotationStrategy) { 236 return new Key<T>(type, annotationStrategy); 237 } 238 239 /** 240 * Gets a key for an injection type. 241 */ 242 public static <T> Key<T> get(Class<T> type) { 243 return new Key<T>(type, NullAnnotationStrategy.INSTANCE); 244 } 245 246 /** 247 * Gets a key for an injection type and an annotation type. 248 */ 249 public static <T> Key<T> get(Class<T> type, 250 Class<? extends Annotation> annotationType) { 251 return new Key<T>(type, strategyFor(annotationType)); 252 } 253 254 /** 255 * Gets a key for an injection type and an annotation. 256 */ 257 public static <T> Key<T> get(Class<T> type, Annotation annotation) { 258 return new Key<T>(type, strategyFor(annotation)); 259 } 260 261 /** 262 * Gets a key for an injection type. 263 */ 264 public static Key<?> get(Type type) { 265 return new Key<Object>(type, NullAnnotationStrategy.INSTANCE); 266 } 267 268 /** 269 * Gets a key for an injection type and an annotation type. 270 */ 271 public static Key<?> get(Type type, 272 Class<? extends Annotation> annotationType) { 273 return new Key<Object>(type, strategyFor(annotationType)); 274 } 275 276 /** 277 * Gets a key for an injection type and an annotation. 278 */ 279 public static Key<?> get(Type type, Annotation annotation) { 280 return new Key<Object>(type, strategyFor(annotation)); 281 } 282 283 /** 284 * Gets a key for an injection type. 285 */ 286 public static <T> Key<T> get(TypeLiteral<T> typeLiteral) { 287 return new Key<T>(typeLiteral, NullAnnotationStrategy.INSTANCE); 288 } 289 290 /** 291 * Gets a key for an injection type and an annotation type. 292 */ 293 public static <T> Key<T> get(TypeLiteral<T> typeLiteral, 294 Class<? extends Annotation> annotationType) { 295 return new Key<T>(typeLiteral, strategyFor(annotationType)); 296 } 297 298 /** 299 * Gets a key for an injection type and an annotation. 300 */ 301 public static <T> Key<T> get(TypeLiteral<T> typeLiteral, 302 Annotation annotation) { 303 return new Key<T>(typeLiteral, strategyFor(annotation)); 304 } 305 306 /** 307 * Returns a new key of the specified type with the same annotation as this 308 * key. 309 * 310 * @since 3.0 311 */ 312 public <T> Key<T> ofType(Class<T> type) { 313 return new Key<T>(type, annotationStrategy); 314 } 315 316 /** 317 * Returns a new key of the specified type with the same annotation as this 318 * key. 319 * 320 * @since 3.0 321 */ 322 public Key<?> ofType(Type type) { 323 return new Key<Object>(type, annotationStrategy); 324 } 325 326 /** 327 * Returns a new key of the specified type with the same annotation as this 328 * key. 329 * 330 * @since 3.0 331 */ 332 public <T> Key<T> ofType(TypeLiteral<T> type) { 333 return new Key<T>(type, annotationStrategy); 334 } 335 336 /** 337 * Returns true if this key has annotation attributes. 338 * 339 * @since 3.0 340 */ 341 public boolean hasAttributes() { 342 return annotationStrategy.hasAttributes(); 343 } 344 345 /** 346 * Returns this key without annotation attributes, i.e. with only the 347 * annotation type. 348 * 349 * @since 3.0 350 */ 351 public Key<T> withoutAttributes() { 352 return new Key<T>(typeLiteral, annotationStrategy.withoutAttributes()); 353 } 354 355 interface AnnotationStrategy { 356 Annotation getAnnotation(); 357 Class<? extends Annotation> getAnnotationType(); 358 boolean hasAttributes(); 359 AnnotationStrategy withoutAttributes(); 360 } 361 362 /** 363 * Gets the strategy for an annotation. 364 */ 365 static AnnotationStrategy strategyFor(Annotation annotation) { 366 checkNotNull(annotation, "annotation"); 367 Class<? extends Annotation> annotationType = annotation.annotationType(); 368 ensureRetainedAtRuntime(annotationType); 369 ensureIsBindingAnnotation(annotationType); 370 371 if (Annotations.isMarker(annotationType)) { 372 return new AnnotationTypeStrategy(annotationType, annotation); 373 } 374 375 return new AnnotationInstanceStrategy(Annotations.canonicalizeIfNamed(annotation)); 376 } 377 378 /** 379 * Gets the strategy for an annotation type. 380 */ 381 static AnnotationStrategy strategyFor(Class<? extends Annotation> annotationType) { 382 annotationType = Annotations.canonicalizeIfNamed(annotationType); 383 if (isAllDefaultMethods(annotationType)) { 384 return strategyFor(generateAnnotation(annotationType)); 385 } 386 387 checkNotNull(annotationType, "annotation type"); 388 ensureRetainedAtRuntime(annotationType); 389 ensureIsBindingAnnotation(annotationType); 390 return new AnnotationTypeStrategy(annotationType, null); 391 392 } 393 394 private static void ensureRetainedAtRuntime( 395 Class<? extends Annotation> annotationType) { 396 checkArgument(Annotations.isRetainedAtRuntime(annotationType), 397 "%s is not retained at runtime. Please annotate it with @Retention(RUNTIME).", 398 annotationType.getName()); 399 } 400 401 private static void ensureIsBindingAnnotation(Class<? extends Annotation> annotationType) { 402 checkArgument(Annotations.isBindingAnnotation(annotationType), 403 "%s is not a binding annotation. Please annotate it with @BindingAnnotation.", 404 annotationType.getName()); 405 } 406 407 static enum NullAnnotationStrategy implements AnnotationStrategy { 408 INSTANCE; 409 410 public boolean hasAttributes() { 411 return false; 412 } 413 414 public AnnotationStrategy withoutAttributes() { 415 throw new UnsupportedOperationException("Key already has no attributes."); 416 } 417 418 public Annotation getAnnotation() { 419 return null; 420 } 421 422 public Class<? extends Annotation> getAnnotationType() { 423 return null; 424 } 425 426 @Override public String toString() { 427 return "[none]"; 428 } 429 } 430 431 // this class not test-covered 432 static class AnnotationInstanceStrategy implements AnnotationStrategy { 433 434 final Annotation annotation; 435 436 AnnotationInstanceStrategy(Annotation annotation) { 437 this.annotation = checkNotNull(annotation, "annotation"); 438 } 439 440 public boolean hasAttributes() { 441 return true; 442 } 443 444 public AnnotationStrategy withoutAttributes() { 445 return new AnnotationTypeStrategy(getAnnotationType(), annotation); 446 } 447 448 public Annotation getAnnotation() { 449 return annotation; 450 } 451 452 public Class<? extends Annotation> getAnnotationType() { 453 return annotation.annotationType(); 454 } 455 456 @Override public boolean equals(Object o) { 457 if (!(o instanceof AnnotationInstanceStrategy)) { 458 return false; 459 } 460 461 AnnotationInstanceStrategy other = (AnnotationInstanceStrategy) o; 462 return annotation.equals(other.annotation); 463 } 464 465 @Override public int hashCode() { 466 return annotation.hashCode(); 467 } 468 469 @Override public String toString() { 470 return annotation.toString(); 471 } 472 } 473 474 static class AnnotationTypeStrategy implements AnnotationStrategy { 475 476 final Class<? extends Annotation> annotationType; 477 478 // Keep the instance around if we have it so the client can request it. 479 final Annotation annotation; 480 481 AnnotationTypeStrategy(Class<? extends Annotation> annotationType, 482 Annotation annotation) { 483 this.annotationType = checkNotNull(annotationType, "annotation type"); 484 this.annotation = annotation; 485 } 486 487 public boolean hasAttributes() { 488 return false; 489 } 490 491 public AnnotationStrategy withoutAttributes() { 492 throw new UnsupportedOperationException("Key already has no attributes."); 493 } 494 495 public Annotation getAnnotation() { 496 return annotation; 497 } 498 499 public Class<? extends Annotation> getAnnotationType() { 500 return annotationType; 501 } 502 503 @Override public boolean equals(Object o) { 504 if (!(o instanceof AnnotationTypeStrategy)) { 505 return false; 506 } 507 508 AnnotationTypeStrategy other = (AnnotationTypeStrategy) o; 509 return annotationType.equals(other.annotationType); 510 } 511 512 @Override public int hashCode() { 513 return annotationType.hashCode(); 514 } 515 516 @Override public String toString() { 517 return "@" + annotationType.getName(); 518 } 519 } 520 } 521