• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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