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