Home | History | Annotate | Download | only in inject
      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 (at) 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")
     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