1 /* 2 * Copyright (C) 2015 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.internal.codegen; 17 18 import com.google.auto.value.AutoValue; 19 import com.google.common.base.Optional; 20 import com.google.common.collect.FluentIterable; 21 import com.google.common.collect.ImmutableMap; 22 import com.google.common.collect.ImmutableSet; 23 import com.google.common.collect.ImmutableSetMultimap; 24 import com.google.common.collect.Iterables; 25 import com.google.common.collect.Multimap; 26 27 import static com.google.common.base.Preconditions.checkArgument; 28 import static com.google.common.base.Preconditions.checkState; 29 import static dagger.internal.codegen.ContributionBinding.contributionTypeFor; 30 31 /** 32 * The collection of bindings that have been resolved for a binding key. 33 * 34 * @author Gregory Kick 35 */ 36 @AutoValue 37 abstract class ResolvedBindings { 38 /** 39 * The binding key for which the {@link #bindings()} have been resolved. 40 */ 41 abstract BindingKey bindingKey(); 42 43 /** 44 * The component in which the bindings in {@link #ownedBindings()}, 45 * {@link #ownedContributionBindings()}, and {@link #ownedMembersInjectionBinding()} were 46 * resolved. 47 */ 48 abstract ComponentDescriptor owningComponent(); 49 50 /** 51 * The contribution bindings for {@link #bindingKey()} that were resolved in 52 * {@link #owningComponent()} or its ancestor components, keyed by the component in which the 53 * binding was resolved. If {@link #bindingKey()}'s kind is not 54 * {@link BindingKey.Kind#CONTRIBUTION}, this is empty. 55 */ 56 abstract ImmutableSetMultimap<ComponentDescriptor, ContributionBinding> allContributionBindings(); 57 58 /** 59 * The members-injection bindings for {@link #bindingKey()} that were resolved in 60 * {@link #owningComponent()} or its ancestor components, keyed by the component in which the 61 * binding was resolved. If {@link #bindingKey()}'s kind is not 62 * {@link BindingKey.Kind#MEMBERS_INJECTION}, this is empty. 63 */ 64 abstract ImmutableMap<ComponentDescriptor, MembersInjectionBinding> allMembersInjectionBindings(); 65 66 /** 67 * All bindings for {@link #bindingKey()}, regardless of in which component they were resolved. 68 */ 69 ImmutableSet<? extends Binding> bindings() { 70 switch (bindingKey().kind()) { 71 case CONTRIBUTION: 72 return contributionBindings(); 73 74 case MEMBERS_INJECTION: 75 return ImmutableSet.copyOf(membersInjectionBinding().asSet()); 76 77 default: 78 throw new AssertionError(bindingKey()); 79 } 80 } 81 82 /** 83 * All bindings for {@link #bindingKey()} that were resolved in {@link #owningComponent()}. 84 */ 85 ImmutableSet<? extends Binding> ownedBindings() { 86 switch (bindingKey().kind()) { 87 case CONTRIBUTION: 88 return ownedContributionBindings(); 89 90 case MEMBERS_INJECTION: 91 return ImmutableSet.copyOf(ownedMembersInjectionBinding().asSet()); 92 93 default: 94 throw new AssertionError(bindingKey()); 95 } 96 } 97 98 /** 99 * All contribution bindings, regardless of owning component. 100 * 101 * @throws IllegalStateException if {@link #bindingKey()} is not a 102 * {@link BindingKey.Kind#CONTRIBUTION}. 103 */ 104 ImmutableSet<ContributionBinding> contributionBindings() { 105 checkState(bindingKey().kind().equals(BindingKey.Kind.CONTRIBUTION)); 106 return ImmutableSet.copyOf(allContributionBindings().values()); 107 } 108 109 /** 110 * The contribution bindings that were resolved in {@link #owningComponent()}. 111 * 112 * @throws IllegalStateException if {@link #bindingKey()} is not a 113 * {@link BindingKey.Kind#CONTRIBUTION}. 114 */ 115 ImmutableSet<ContributionBinding> ownedContributionBindings() { 116 checkState(bindingKey().kind().equals(BindingKey.Kind.CONTRIBUTION)); 117 return allContributionBindings().get(owningComponent()); 118 } 119 120 /** 121 * The members-injection binding, regardless of owning component. 122 * 123 * @throws IllegalStateException if {@link #bindingKey()} is not a 124 * {@link BindingKey.Kind#MEMBERS_INJECTION}. 125 */ 126 Optional<MembersInjectionBinding> membersInjectionBinding() { 127 checkState(bindingKey().kind().equals(BindingKey.Kind.MEMBERS_INJECTION)); 128 ImmutableSet<MembersInjectionBinding> membersInjectionBindings = 129 FluentIterable.from(allMembersInjectionBindings().values()).toSet(); 130 return membersInjectionBindings.isEmpty() 131 ? Optional.<MembersInjectionBinding>absent() 132 : Optional.of(Iterables.getOnlyElement(membersInjectionBindings)); 133 } 134 135 /** 136 * The members-injection binding that was resolved in {@link #owningComponent()}. 137 * 138 * @throws IllegalStateException if {@link #bindingKey()} is not a 139 * {@link BindingKey.Kind#MEMBERS_INJECTION}. 140 */ 141 Optional<MembersInjectionBinding> ownedMembersInjectionBinding() { 142 checkState(bindingKey().kind().equals(BindingKey.Kind.MEMBERS_INJECTION)); 143 return Optional.fromNullable(allMembersInjectionBindings().get(owningComponent())); 144 } 145 146 /** 147 * Creates a {@link ResolvedBindings} for contribution bindings. 148 */ 149 static ResolvedBindings forContributionBindings( 150 BindingKey bindingKey, 151 ComponentDescriptor owningComponent, 152 Multimap<ComponentDescriptor, ? extends ContributionBinding> contributionBindings) { 153 checkArgument(bindingKey.kind().equals(BindingKey.Kind.CONTRIBUTION)); 154 return new AutoValue_ResolvedBindings( 155 bindingKey, 156 owningComponent, 157 ImmutableSetMultimap.<ComponentDescriptor, ContributionBinding>copyOf(contributionBindings), 158 ImmutableMap.<ComponentDescriptor, MembersInjectionBinding>of()); 159 } 160 161 /** 162 * Creates a {@link ResolvedBindings} for contribution bindings. 163 */ 164 static ResolvedBindings forContributionBindings( 165 BindingKey bindingKey, 166 ComponentDescriptor owningComponent, 167 ContributionBinding... ownedContributionBindings) { 168 return forContributionBindings( 169 bindingKey, 170 owningComponent, 171 ImmutableSetMultimap.<ComponentDescriptor, ContributionBinding>builder() 172 .putAll(owningComponent, ownedContributionBindings) 173 .build()); 174 } 175 176 /** 177 * Creates a {@link ResolvedBindings} for members injection bindings. 178 */ 179 static ResolvedBindings forMembersInjectionBinding( 180 BindingKey bindingKey, 181 ComponentDescriptor owningComponent, 182 MembersInjectionBinding ownedMembersInjectionBinding) { 183 checkArgument(bindingKey.kind().equals(BindingKey.Kind.MEMBERS_INJECTION)); 184 return new AutoValue_ResolvedBindings( 185 bindingKey, 186 owningComponent, 187 ImmutableSetMultimap.<ComponentDescriptor, ContributionBinding>of(), 188 ImmutableMap.of(owningComponent, ownedMembersInjectionBinding)); 189 } 190 191 /** 192 * Creates a {@link ResolvedBindings} appropriate for when there are no bindings for the key. 193 */ 194 static ResolvedBindings noBindings(BindingKey bindingKey, ComponentDescriptor owningComponent) { 195 return new AutoValue_ResolvedBindings( 196 bindingKey, 197 owningComponent, 198 ImmutableSetMultimap.<ComponentDescriptor, ContributionBinding>of(), 199 ImmutableMap.<ComponentDescriptor, MembersInjectionBinding>of()); 200 } 201 202 /** 203 * Returns a {@code ResolvedBindings} with the same {@link #bindingKey()} and {@link #bindings()} 204 * as this one, but no {@link #ownedBindings()}. 205 */ 206 ResolvedBindings asInheritedIn(ComponentDescriptor owningComponent) { 207 return new AutoValue_ResolvedBindings( 208 bindingKey(), owningComponent, allContributionBindings(), allMembersInjectionBindings()); 209 } 210 211 /** 212 * {@code true} if this is a multibindings contribution. 213 */ 214 boolean isMultibindings() { 215 return bindingKey().kind().equals(BindingKey.Kind.CONTRIBUTION) 216 && !contributionBindings().isEmpty() 217 && contributionTypeFor(contributionBindings()).isMultibinding(); 218 } 219 220 /** 221 * {@code true} if this is a unique contribution binding. 222 */ 223 boolean isUniqueContribution() { 224 return bindingKey().kind().equals(BindingKey.Kind.CONTRIBUTION) 225 && !contributionBindings().isEmpty() 226 && !contributionTypeFor(contributionBindings()).isMultibinding(); 227 } 228 } 229