• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 The Dagger Authors.
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 dagger.functional.subcomponent;
18 
19 import dagger.Binds;
20 import dagger.Component;
21 import dagger.Module;
22 import dagger.Provides;
23 import dagger.Subcomponent;
24 import dagger.multibindings.IntoMap;
25 import dagger.multibindings.IntoSet;
26 import dagger.multibindings.StringKey;
27 import java.util.Map;
28 import java.util.Objects;
29 import java.util.Set;
30 import javax.inject.Inject;
31 
32 final class MultibindingSubcomponents {
33 
34   /** Multibindings for this type are bound only in the parent component. */
35   enum BoundInParent {
36     INSTANCE;
37   }
38 
39   /** Multibindings for this type are bound only in the child component. */
40   enum BoundInChild {
41     INSTANCE;
42   }
43 
44   /** Multibindings for this type are bound in the parent component and the child component. */
45   enum BoundInParentAndChild {
46     IN_PARENT,
47     IN_CHILD;
48   }
49 
50   static final class RequiresMultibindings<T> {
51     private final Set<T> set;
52     private final Map<String, T> map;
53 
54     @Inject
RequiresMultibindings(Set<T> set, Map<String, T> map)55     RequiresMultibindings(Set<T> set, Map<String, T> map) {
56       this.set = set;
57       this.map = map;
58     }
59 
set()60     Set<T> set() {
61       return set;
62     }
63 
map()64     Map<String, T> map() {
65       return map;
66     }
67 
68     @Override
equals(Object obj)69     public boolean equals(Object obj) {
70       return obj instanceof RequiresMultibindings<?>
71           && set.equals(((RequiresMultibindings<?>) obj).set)
72           && map.equals(((RequiresMultibindings<?>) obj).map);
73     }
74 
75     @Override
hashCode()76     public int hashCode() {
77       return Objects.hash(set, map);
78     }
79 
80     @Override
toString()81     public String toString() {
82       return String.format(
83           "%s{set=%s, map=%s}", RequiresMultibindings.class.getSimpleName(), set, map);
84     }
85   }
86 
87   @Module
88   abstract static class ParentMultibindingModule {
89 
90     @Provides
91     @IntoSet
onlyInParentElement()92     static BoundInParent onlyInParentElement() {
93       return BoundInParent.INSTANCE;
94     }
95 
96     @Provides
97     @IntoMap
98     @StringKey("parent key")
onlyInParentEntry()99     static BoundInParent onlyInParentEntry() {
100       return BoundInParent.INSTANCE;
101     }
102 
103     @Provides
104     @IntoSet
inParentAndChildElement()105     static BoundInParentAndChild inParentAndChildElement() {
106       return BoundInParentAndChild.IN_PARENT;
107     }
108 
109     @Provides
110     @IntoMap
111     @StringKey("parent key")
inParentAndChildEntry()112     static BoundInParentAndChild inParentAndChildEntry() {
113       return BoundInParentAndChild.IN_PARENT;
114     }
115 
116     /* This is not static because otherwise we have no tests that cover the case where a
117      * subcomponent uses a module instance installed onto a parent component. */
118     @Binds
119     @IntoSet
120     abstract RequiresMultibindings<BoundInParentAndChild>
requiresMultibindingsInParentAndChildElement( RequiresMultibindings<BoundInParentAndChild> requiresMultibindingsInParentAndChild)121         requiresMultibindingsInParentAndChildElement(
122             RequiresMultibindings<BoundInParentAndChild> requiresMultibindingsInParentAndChild);
123   }
124 
125   @Module
126   static final class ChildMultibindingModule {
127 
128     @Provides
129     @IntoSet
inParentAndChildElement()130     static BoundInParentAndChild inParentAndChildElement() {
131       return BoundInParentAndChild.IN_CHILD;
132     }
133 
134     @Provides
135     @IntoMap
136     @StringKey("child key")
inParentAndChildEntry()137     static BoundInParentAndChild inParentAndChildEntry() {
138       return BoundInParentAndChild.IN_CHILD;
139     }
140 
141     @Provides
142     @IntoSet
onlyInChildElement()143     static BoundInChild onlyInChildElement() {
144       return BoundInChild.INSTANCE;
145     }
146 
147     @Provides
148     @IntoMap
149     @StringKey("child key")
onlyInChildEntry()150     static BoundInChild onlyInChildEntry() {
151       return BoundInChild.INSTANCE;
152     }
153   }
154 
155   @Module
156   abstract static class ChildMultibindingModuleWithOnlyBindsMultibindings {
157     @Provides
provideBoundInParentAndChildForBinds()158     static BoundInParentAndChild provideBoundInParentAndChildForBinds() {
159       return BoundInParentAndChild.IN_CHILD;
160     }
161 
162     @Binds
163     @IntoSet
bindsLocalContribution(BoundInParentAndChild instance)164     abstract BoundInParentAndChild bindsLocalContribution(BoundInParentAndChild instance);
165 
166     @Binds
167     @IntoMap
168     @StringKey("child key")
inParentAndChildEntry(BoundInParentAndChild instance)169     abstract BoundInParentAndChild inParentAndChildEntry(BoundInParentAndChild instance);
170 
171     @Provides
provideBoundInChildForBinds()172     static BoundInChild provideBoundInChildForBinds() {
173       return BoundInChild.INSTANCE;
174     }
175 
176     @Binds
177     @IntoSet
inChild(BoundInChild instance)178     abstract BoundInChild inChild(BoundInChild instance);
179 
180     @Binds
181     @IntoMap
182     @StringKey("child key")
inChildEntry(BoundInChild instance)183     abstract BoundInChild inChildEntry(BoundInChild instance);
184   }
185 
186   interface ProvidesBoundInParent {
requiresMultibindingsBoundInParent()187     RequiresMultibindings<BoundInParent> requiresMultibindingsBoundInParent();
188   }
189 
190   interface ProvidesBoundInChild {
requiresMultibindingsBoundInChild()191     RequiresMultibindings<BoundInChild> requiresMultibindingsBoundInChild();
192   }
193 
194   interface ProvidesBoundInParentAndChild {
requiresMultibindingsBoundInParentAndChild()195     RequiresMultibindings<BoundInParentAndChild> requiresMultibindingsBoundInParentAndChild();
196   }
197 
198   interface ProvidesSetOfRequiresMultibindings {
setOfRequiresMultibindingsInParentAndChild()199     Set<RequiresMultibindings<BoundInParentAndChild>> setOfRequiresMultibindingsInParentAndChild();
200   }
201 
202   interface ParentWithProvision
203       extends ProvidesBoundInParent, ProvidesBoundInParentAndChild,
204           ProvidesSetOfRequiresMultibindings {}
205 
206   interface HasChildWithProvision {
childWithProvision()207     ChildWithProvision childWithProvision();
208   }
209 
210   interface HasChildWithoutProvision {
childWithoutProvision()211     ChildWithoutProvision childWithoutProvision();
212   }
213 
214   @Component(modules = ParentMultibindingModule.class)
215   interface ParentWithoutProvisionHasChildWithoutProvision extends HasChildWithoutProvision {}
216 
217   @Component(modules = ParentMultibindingModule.class)
218   interface ParentWithoutProvisionHasChildWithProvision extends HasChildWithProvision {}
219 
220   @Component(modules = ParentMultibindingModule.class)
221   interface ParentWithProvisionHasChildWithoutProvision
222       extends ParentWithProvision, HasChildWithoutProvision {}
223 
224   @Component(modules = ParentMultibindingModule.class)
225   interface ParentWithProvisionHasChildWithProvision
226       extends ParentWithProvision, HasChildWithProvision {}
227 
228   @Subcomponent(modules = ChildMultibindingModule.class)
229   interface ChildWithoutProvision {
grandchild()230     Grandchild grandchild();
231   }
232 
233   @Subcomponent(modules = ChildMultibindingModule.class)
234   interface ChildWithProvision
235       extends ProvidesBoundInParent, ProvidesBoundInParentAndChild, ProvidesBoundInChild,
236           ProvidesSetOfRequiresMultibindings {
237 
grandchild()238     Grandchild grandchild();
239   }
240 
241   @Subcomponent
242   interface Grandchild
243       extends ProvidesBoundInParent, ProvidesBoundInParentAndChild, ProvidesBoundInChild,
244           ProvidesSetOfRequiresMultibindings {}
245 
246   @Component(modules = ParentMultibindingModule.class)
247   interface ParentWithProvisionHasChildWithBinds extends ParentWithProvision {
childWithBinds()248     ChildWithBinds childWithBinds();
249   }
250 
251   @Subcomponent(modules = ChildMultibindingModuleWithOnlyBindsMultibindings.class)
252   interface ChildWithBinds extends ChildWithProvision {}
253 
254 }
255