1 16 17 package com.google.inject; 18 19 import static com.google.inject.util.Objects.nonNull; 20 import com.google.inject.util.StackTraceElements; 21 import com.google.inject.util.ToStringBuilder; 22 import com.google.inject.util.Annotations; 23 import java.lang.annotation.Annotation ; 24 import java.lang.reflect.Member ; 25 import java.lang.reflect.Type ; 26 27 46 public abstract class Key<T> { 47 48 final AnnotationStrategy annotationStrategy; 49 50 final TypeLiteral<T> typeLiteral; 51 final int hashCode; 52 53 65 @SuppressWarnings ("unchecked") 66 protected Key(Class <? extends Annotation > annotationType) { 67 this.annotationStrategy = strategyFor(annotationType); 68 this.typeLiteral 69 = (TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass()); 70 this.hashCode = computeHashCode(); 71 } 72 73 85 @SuppressWarnings ("unchecked") 86 protected Key(Annotation annotation) { 87 this.annotationStrategy = strategyFor(annotation); 89 this.typeLiteral 90 = (TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass()); 91 this.hashCode = computeHashCode(); 92 } 93 94 105 @SuppressWarnings ("unchecked") 106 protected Key() { 107 this.annotationStrategy = NULL_STRATEGY; 108 this.typeLiteral 109 = (TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass()); 110 this.hashCode = computeHashCode(); 111 } 112 113 116 @SuppressWarnings ("unchecked") 117 private Key(Type type, AnnotationStrategy annotationStrategy) { 118 this.annotationStrategy = annotationStrategy; 119 this.typeLiteral = (TypeLiteral<T>) TypeLiteral.get(type); 120 this.hashCode = computeHashCode(); 121 } 122 123 124 private Key(TypeLiteral<T> typeLiteral, 125 AnnotationStrategy annotationStrategy) { 126 this.annotationStrategy = annotationStrategy; 127 this.typeLiteral = typeLiteral; 128 this.hashCode = computeHashCode(); 129 } 130 131 private int computeHashCode() { 132 return typeLiteral.hashCode() * 31 + annotationStrategy.hashCode(); 133 } 134 135 138 public TypeLiteral<T> getTypeLiteral() { 139 return typeLiteral; 140 } 141 142 145 public Class <? extends Annotation > getAnnotationType() { 146 return annotationStrategy.getAnnotationType(); 147 } 148 149 152 public Annotation getAnnotation() { 153 return annotationStrategy.getAnnotation(); 154 } 155 156 boolean hasAnnotationType() { 157 return annotationStrategy.getAnnotationType() != null; 158 } 159 160 String getAnnotationName() { 161 Annotation annotation = annotationStrategy.getAnnotation(); 162 if (annotation != null) { 163 return annotation.toString(); 164 } 165 166 return annotationStrategy.getAnnotationType().toString(); 168 } 169 170 public int hashCode() { 171 return this.hashCode; 172 } 173 174 Class <? super T> getRawType() { 175 return typeLiteral.getRawType(); 176 } 177 178 public 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 public String toString() { 191 return new ToStringBuilder(Key.class) 192 .add("type", typeLiteral) 193 .add("annotation", annotationStrategy) 194 .toString(); 195 } 196 197 200 static <T> Key<T> get(Class <T> type, 201 AnnotationStrategy annotationStrategy) { 202 return new SimpleKey<T>(type, annotationStrategy); 203 } 204 205 208 public static <T> Key<T> get(Class <T> type) { 209 return new SimpleKey<T>(type, NULL_STRATEGY); 210 } 211 212 215 public static <T> Key<T> get(Class <T> type, 216 Class <? extends Annotation > annotationType) { 217 return new SimpleKey<T>(type, strategyFor(annotationType)); 218 } 219 220 223 public static <T> Key<T> get(Class <T> type, Annotation annotation) { 224 return new SimpleKey<T>(type, strategyFor(annotation)); 225 } 226 227 230 public static Key<?> get(Type type) { 231 return new SimpleKey<Object >(type, NULL_STRATEGY); 232 } 233 234 237 public static Key<?> get(Type type, 238 Class <? extends Annotation > annotationType) { 239 return new SimpleKey<Object >(type, strategyFor(annotationType)); 240 } 241 242 245 public static Key<?> get(Type type, Annotation annotation) { 246 return new SimpleKey<Object >(type, strategyFor(annotation)); 247 } 248 249 252 public static <T> Key<T> get(TypeLiteral<T> typeLiteral) { 253 return new SimpleKey<T>(typeLiteral, NULL_STRATEGY); 254 } 255 256 259 public static <T> Key<T> get(TypeLiteral<T> typeLiteral, 260 Class <? extends Annotation > annotationType) { 261 return new SimpleKey<T>(typeLiteral, strategyFor(annotationType)); 262 } 263 264 267 public static <T> Key<T> get(TypeLiteral<T> typeLiteral, 268 Annotation annotation) { 269 return new SimpleKey<T>(typeLiteral, strategyFor(annotation)); 270 } 271 272 275 static Key<?> get(Type type, Member member, Annotation [] annotations, 276 ErrorHandler errorHandler) { 277 Annotation found = null; 278 for (Annotation annotation : annotations) { 279 if (annotation.annotationType().getAnnotation(BindingAnnotation.class) != null) { 280 if (found == null) { 281 found = annotation; 282 } else { 283 errorHandler.handle(StackTraceElements.forMember(member), 284 ErrorMessages.DUPLICATE_ANNOTATIONS, found, annotation); 285 } 286 } 287 } 288 Key<?> key = found == null ? Key.get(type) : Key.get(type, found); 289 return key; 290 } 291 292 296 <T> Key<T> ofType(Class <T> type) { 297 return new SimpleKey<T>(type, annotationStrategy); 298 } 299 300 304 Key<?> ofType(Type type) { 305 return new SimpleKey<Object >(type, annotationStrategy); 306 } 307 308 312 boolean hasAttributes() { 313 return annotationStrategy.hasAttributes(); 314 } 315 316 320 Key<T> withoutAttributes() { 321 return new SimpleKey<T>(typeLiteral, annotationStrategy.withoutAttributes()); 322 } 323 324 private static class SimpleKey<T> extends Key<T> { 325 326 private SimpleKey(Type type, AnnotationStrategy annotationStrategy) { 327 super(type, annotationStrategy); 328 } 329 330 private SimpleKey(TypeLiteral<T> typeLiteral, 331 AnnotationStrategy annotationStrategy) { 332 super(typeLiteral, annotationStrategy); 333 } 334 } 335 336 interface AnnotationStrategy { 337 338 Annotation getAnnotation(); 339 Class <? extends Annotation > getAnnotationType(); 340 boolean hasAttributes(); 341 AnnotationStrategy withoutAttributes(); 342 } 343 344 static final AnnotationStrategy NULL_STRATEGY = new AnnotationStrategy() { 345 346 public boolean hasAttributes() { 347 return false; 348 } 349 350 public AnnotationStrategy withoutAttributes() { 351 throw new UnsupportedOperationException ("Key already has no attributes."); 352 } 353 354 public Annotation getAnnotation() { 355 return null; 356 } 357 358 public Class <? extends Annotation > getAnnotationType() { 359 return null; 360 } 361 362 public boolean equals(Object o) { 363 return o == NULL_STRATEGY; 364 } 365 366 public int hashCode() { 367 return 0; 368 } 369 370 public String toString() { 371 return "[none]"; 372 } 373 }; 374 375 378 static boolean isMarker(Class <? extends Annotation > annotationType) { 379 return annotationType.getDeclaredMethods().length == 0; 380 } 381 382 385 static AnnotationStrategy strategyFor(Annotation annotation) { 386 nonNull(annotation, "annotation"); 387 Class <? extends Annotation > annotationType = annotation.annotationType(); 388 ensureRetainedAtRuntime(annotationType); 389 ensureIsBindingAnnotation(annotationType); 390 return new AnnotationInstanceStrategy(annotation); 391 } 392 393 396 static AnnotationStrategy strategyFor( 397 Class <? extends Annotation > annotationType) { 398 nonNull(annotationType, "annotation type"); 399 ensureRetainedAtRuntime(annotationType); 400 ensureIsBindingAnnotation(annotationType); 401 return new AnnotationTypeStrategy(annotationType, null); 402 } 403 404 private static void ensureRetainedAtRuntime( 405 Class <? extends Annotation > annotationType) { 406 if (!Annotations.isRetainedAtRuntime(annotationType)) { 407 throw new IllegalArgumentException (annotationType.getName() 408 + " is not retained at runtime." 409 + " Please annotate it with @Retention(RUNTIME)."); 410 } 411 } 412 413 private static void ensureIsBindingAnnotation( 414 Class <? extends Annotation > annotationType) { 415 if (!isBindingAnnotation(annotationType)) { 416 throw new IllegalArgumentException (annotationType.getName() 417 + " is not a binding annotation." 418 + " Please annotate it with @BindingAnnotation."); 419 } 420 } 421 422 static class AnnotationInstanceStrategy implements AnnotationStrategy { 424 425 final Annotation annotation; 426 427 AnnotationInstanceStrategy(Annotation annotation) { 428 this.annotation = nonNull(annotation, "annotation"); 429 } 430 431 public boolean hasAttributes() { 432 return true; 433 } 434 435 public AnnotationStrategy withoutAttributes() { 436 return new AnnotationTypeStrategy(getAnnotationType(), annotation); 437 } 438 439 public Annotation getAnnotation() { 440 return annotation; 441 } 442 443 public Class <? extends Annotation > getAnnotationType() { 444 return annotation.annotationType(); 445 } 446 447 public boolean equals(Object o) { 448 if (!(o instanceof AnnotationInstanceStrategy)) { 449 return false; 450 } 451 452 AnnotationInstanceStrategy other = (AnnotationInstanceStrategy) o; 453 return annotation.equals(other.annotation); 454 } 455 456 public int hashCode() { 457 return annotation.hashCode(); 458 } 459 460 public String toString() { 461 return annotation.toString(); 462 } 463 } 464 465 static class AnnotationTypeStrategy implements AnnotationStrategy { 466 467 final Class <? extends Annotation > annotationType; 468 469 final Annotation annotation; 471 472 AnnotationTypeStrategy(Class <? extends Annotation > annotationType, 473 Annotation annotation) { 474 this.annotationType = nonNull(annotationType, "annotation type"); 475 this.annotation = annotation; 476 } 477 478 public boolean hasAttributes() { 479 return false; 480 } 481 482 public AnnotationStrategy withoutAttributes() { 483 throw new UnsupportedOperationException ("Key already has no attributes."); 484 } 485 486 public Annotation getAnnotation() { 487 return annotation; 488 } 489 490 public Class <? extends Annotation > getAnnotationType() { 491 return annotationType; 492 } 493 494 public boolean equals(Object o) { 495 if (!(o instanceof AnnotationTypeStrategy)) { 496 return false; 497 } 498 499 AnnotationTypeStrategy other = (AnnotationTypeStrategy) o; 500 return annotationType.equals(other.annotationType); 501 } 502 503 public int hashCode() { 504 return annotationType.hashCode(); 505 } 506 507 public String toString() { 508 return "@" + annotationType.getName(); 509 } 510 } 511 512 static boolean isBindingAnnotation(Annotation annotation) { 513 return isBindingAnnotation(annotation.annotationType()); 514 } 515 516 static boolean isBindingAnnotation( 517 Class <? extends Annotation > annotationType) { 518 return annotationType.isAnnotationPresent(BindingAnnotation.class); 519 } 520 } 521 | Popular Tags |