1 /*
2  * Copyright (C) 2014 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 package dagger;
17 
18 import dagger.internal.Beta;
19 import java.lang.annotation.Documented;
20 import java.lang.annotation.Retention;
21 import java.lang.annotation.Target;
22 import java.util.Map;
23 
24 import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
25 import static java.lang.annotation.RetentionPolicy.RUNTIME;
26 
27 /**
28  * Identifies annotation types that are used to associate keys with values returned by
29  * {@linkplain Provides provider methods} in order to compose a {@linkplain Provides.Type#MAP map}.
30  *
31  * <p>Every provider method annotated with {@code @Provides(type = MAP)} must also have an
32  * annotation that identifies the key for that map entry. That annotation's type must be annotated
33  * with {@code @MapKey}.
34  *
35  * <p>Typically, the key annotation has a single member, whose value is used as the map key.
36  *
37  * <p>For example, to add an entry to a {@code Map<SomeEnum, Integer>} with key
38  * {@code SomeEnum.FOO}, you could use an annotation called {@code @SomeEnumKey}:
39  *
40  * <pre><code>
41  * {@literal @}MapKey
42  * {@literal @}interface SomeEnumKey {
43  *   SomeEnum value();
44  * }
45  *
46  * {@literal @}Module
47  * class SomeModule {
48  *   {@literal @}Provides(type = MAP)
49  *   {@literal @}SomeEnumKey(SomeEnum.FOO)
50  *   Integer provideFooValue() {
51  *     return 2;
52  *   }
53  * }
54  *
55  * class SomeInjectedType {
56  *   {@literal @}Inject
57  *   SomeInjectedType(Map<SomeEnum, Integer> map) {
58  *     assert map.get(SomeEnum.FOO) == 2;
59  *   }
60  * }
61  * </code></pre>
62  *
63  * <p>If {@code unwrapValue} is true, the annotation's single member can be any type except an
64  * array.
65  *
66  * <p>See {@link dagger.mapkeys} for standard unwrapped map key annotations for keys that are boxed
67  * primitives, strings, or classes.
68  *
69  * <h2>Annotations as keys</h2>
70  *
71  * <p>If {@link #unwrapValue} is false, then the annotation itself is used as the map key. For
72  * example, to add an entry to a {@code Map<MyMapKey, Integer>} map:
73  *
74  * <pre><code>
75  * {@literal @}MapKey(unwrapValue = false)
76  * {@literal @}interface MyMapKey {
77  *   String someString();
78  *   MyEnum someEnum();
79  * }
80  *
81  * {@literal @}Module
82  * class SomeModule {
83  *   {@literal @}Provides(type = MAP)
84  *   {@literal @}MyMapKey(someString = "foo", someEnum = BAR)
85  *   Integer provideFooBarValue() {
86  *     return 2;
87  *   }
88  * }
89  *
90  * class SomeInjectedType {
91  *   {@literal @}Inject
92  *   SomeInjectedType(Map<MyMapKey, Integer> map) {
93  *     assert map.get(new MyMapKeyImpl("foo", MyEnum.BAR)) == 2;
94  *   }
95  * }
96  * </code></pre>
97  *
98  * <p>(Note that there must be a class {@code MyMapKeyImpl} that implements {@code MyMapKey} in
99  * order to call {@link Map#get(Object)} on the provided map.)
100  *
101  */
102 @Documented
103 @Target(ANNOTATION_TYPE)
104 @Retention(RUNTIME)
105 @Beta
106 public @interface MapKey {
107   /**
108    * True to use the value of the single member of the annotated annotation as the map key; false
109    * to use the annotation instance as the map key.
110    *
111    * <p>If true, the single member must not be an array.
112    */
unwrapValue()113   boolean unwrapValue() default true;
114 }
115