/* * Copyright (C) 2015 Google, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package dagger.internal.codegen; import com.google.auto.value.AutoValue; import com.google.common.base.Optional; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSetMultimap; import com.google.common.collect.Iterables; import com.google.common.collect.Multimap; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkState; import static dagger.internal.codegen.ContributionBinding.contributionTypeFor; /** * The collection of bindings that have been resolved for a binding key. * * @author Gregory Kick */ @AutoValue abstract class ResolvedBindings { /** * The binding key for which the {@link #bindings()} have been resolved. */ abstract BindingKey bindingKey(); /** * The component in which the bindings in {@link #ownedBindings()}, * {@link #ownedContributionBindings()}, and {@link #ownedMembersInjectionBinding()} were * resolved. */ abstract ComponentDescriptor owningComponent(); /** * The contribution bindings for {@link #bindingKey()} that were resolved in * {@link #owningComponent()} or its ancestor components, keyed by the component in which the * binding was resolved. If {@link #bindingKey()}'s kind is not * {@link BindingKey.Kind#CONTRIBUTION}, this is empty. */ abstract ImmutableSetMultimap<ComponentDescriptor, ContributionBinding> allContributionBindings(); /** * The members-injection bindings for {@link #bindingKey()} that were resolved in * {@link #owningComponent()} or its ancestor components, keyed by the component in which the * binding was resolved. If {@link #bindingKey()}'s kind is not * {@link BindingKey.Kind#MEMBERS_INJECTION}, this is empty. */ abstract ImmutableMap<ComponentDescriptor, MembersInjectionBinding> allMembersInjectionBindings(); /** * All bindings for {@link #bindingKey()}, regardless of in which component they were resolved. */ ImmutableSet<? extends Binding> bindings() { switch (bindingKey().kind()) { case CONTRIBUTION: return contributionBindings(); case MEMBERS_INJECTION: return ImmutableSet.copyOf(membersInjectionBinding().asSet()); default: throw new AssertionError(bindingKey()); } } /** * All bindings for {@link #bindingKey()} that were resolved in {@link #owningComponent()}. */ ImmutableSet<? extends Binding> ownedBindings() { switch (bindingKey().kind()) { case CONTRIBUTION: return ownedContributionBindings(); case MEMBERS_INJECTION: return ImmutableSet.copyOf(ownedMembersInjectionBinding().asSet()); default: throw new AssertionError(bindingKey()); } } /** * All contribution bindings, regardless of owning component. * * @throws IllegalStateException if {@link #bindingKey()} is not a * {@link BindingKey.Kind#CONTRIBUTION}. */ ImmutableSet<ContributionBinding> contributionBindings() { checkState(bindingKey().kind().equals(BindingKey.Kind.CONTRIBUTION)); return ImmutableSet.copyOf(allContributionBindings().values()); } /** * The contribution bindings that were resolved in {@link #owningComponent()}. * * @throws IllegalStateException if {@link #bindingKey()} is not a * {@link BindingKey.Kind#CONTRIBUTION}. */ ImmutableSet<ContributionBinding> ownedContributionBindings() { checkState(bindingKey().kind().equals(BindingKey.Kind.CONTRIBUTION)); return allContributionBindings().get(owningComponent()); } /** * The members-injection binding, regardless of owning component. * * @throws IllegalStateException if {@link #bindingKey()} is not a * {@link BindingKey.Kind#MEMBERS_INJECTION}. */ Optional<MembersInjectionBinding> membersInjectionBinding() { checkState(bindingKey().kind().equals(BindingKey.Kind.MEMBERS_INJECTION)); ImmutableSet<MembersInjectionBinding> membersInjectionBindings = FluentIterable.from(allMembersInjectionBindings().values()).toSet(); return membersInjectionBindings.isEmpty() ? Optional.<MembersInjectionBinding>absent() : Optional.of(Iterables.getOnlyElement(membersInjectionBindings)); } /** * The members-injection binding that was resolved in {@link #owningComponent()}. * * @throws IllegalStateException if {@link #bindingKey()} is not a * {@link BindingKey.Kind#MEMBERS_INJECTION}. */ Optional<MembersInjectionBinding> ownedMembersInjectionBinding() { checkState(bindingKey().kind().equals(BindingKey.Kind.MEMBERS_INJECTION)); return Optional.fromNullable(allMembersInjectionBindings().get(owningComponent())); } /** * Creates a {@link ResolvedBindings} for contribution bindings. */ static ResolvedBindings forContributionBindings( BindingKey bindingKey, ComponentDescriptor owningComponent, Multimap<ComponentDescriptor, ? extends ContributionBinding> contributionBindings) { checkArgument(bindingKey.kind().equals(BindingKey.Kind.CONTRIBUTION)); return new AutoValue_ResolvedBindings( bindingKey, owningComponent, ImmutableSetMultimap.<ComponentDescriptor, ContributionBinding>copyOf(contributionBindings), ImmutableMap.<ComponentDescriptor, MembersInjectionBinding>of()); } /** * Creates a {@link ResolvedBindings} for contribution bindings. */ static ResolvedBindings forContributionBindings( BindingKey bindingKey, ComponentDescriptor owningComponent, ContributionBinding... ownedContributionBindings) { return forContributionBindings( bindingKey, owningComponent, ImmutableSetMultimap.<ComponentDescriptor, ContributionBinding>builder() .putAll(owningComponent, ownedContributionBindings) .build()); } /** * Creates a {@link ResolvedBindings} for members injection bindings. */ static ResolvedBindings forMembersInjectionBinding( BindingKey bindingKey, ComponentDescriptor owningComponent, MembersInjectionBinding ownedMembersInjectionBinding) { checkArgument(bindingKey.kind().equals(BindingKey.Kind.MEMBERS_INJECTION)); return new AutoValue_ResolvedBindings( bindingKey, owningComponent, ImmutableSetMultimap.<ComponentDescriptor, ContributionBinding>of(), ImmutableMap.of(owningComponent, ownedMembersInjectionBinding)); } /** * Creates a {@link ResolvedBindings} appropriate for when there are no bindings for the key. */ static ResolvedBindings noBindings(BindingKey bindingKey, ComponentDescriptor owningComponent) { return new AutoValue_ResolvedBindings( bindingKey, owningComponent, ImmutableSetMultimap.<ComponentDescriptor, ContributionBinding>of(), ImmutableMap.<ComponentDescriptor, MembersInjectionBinding>of()); } /** * Returns a {@code ResolvedBindings} with the same {@link #bindingKey()} and {@link #bindings()} * as this one, but no {@link #ownedBindings()}. */ ResolvedBindings asInheritedIn(ComponentDescriptor owningComponent) { return new AutoValue_ResolvedBindings( bindingKey(), owningComponent, allContributionBindings(), allMembersInjectionBindings()); } /** * {@code true} if this is a multibindings contribution. */ boolean isMultibindings() { return bindingKey().kind().equals(BindingKey.Kind.CONTRIBUTION) && !contributionBindings().isEmpty() && contributionTypeFor(contributionBindings()).isMultibinding(); } /** * {@code true} if this is a unique contribution binding. */ boolean isUniqueContribution() { return bindingKey().kind().equals(BindingKey.Kind.CONTRIBUTION) && !contributionBindings().isEmpty() && !contributionTypeFor(contributionBindings()).isMultibinding(); } }