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