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
17package com.google.inject;
18
19import static com.google.common.base.Preconditions.checkArgument;
20import static com.google.common.base.Preconditions.checkNotNull;
21import static com.google.inject.internal.Annotations.generateAnnotation;
22import static com.google.inject.internal.Annotations.isAllDefaultMethods;
23
24import com.google.common.base.Supplier;
25import com.google.common.base.Suppliers;
26import com.google.inject.internal.Annotations;
27import com.google.inject.internal.MoreTypes;
28
29import java.lang.annotation.Annotation;
30import 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 */
55public 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")
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")
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")
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")
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. */
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   */
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   */
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