
dagger.internal.codegen.ResolvedBindings Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dagger-compiler Show documentation
Show all versions of dagger-compiler Show documentation
A fast dependency injector for Android and Java.
/*
* 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.ImmutableListMultimap;
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 dagger.internal.codegen.BindingType.HasBindingType;
import dagger.internal.codegen.ContributionType.HasContributionType;
import dagger.internal.codegen.Key.HasKey;
import dagger.internal.codegen.SourceElement.HasSourceElement;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.Iterables.concat;
import static com.google.common.collect.Iterables.getOnlyElement;
import static dagger.internal.codegen.ContributionType.indexByContributionType;
/**
* The collection of bindings that have been resolved for a binding key. For valid graphs, contains
* exactly one binding.
*
* @author Gregory Kick
*/
@AutoValue
abstract class ResolvedBindings implements HasBindingType, HasContributionType, HasKey {
/**
* 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 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 allMembersInjectionBindings();
@Override
public Key key() {
return bindingKey().key();
}
/**
* The multibinding declarations for {@link #bindingKey()}. If {@link #bindingKey()}'s kind is not
* {@link BindingKey.Kind#CONTRIBUTION}, this is empty.
*/
abstract ImmutableSet multibindingDeclarations();
/**
* 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()}, indexed by the component in which they were resolved.
*/
ImmutableSetMultimap bindingsByComponent() {
return new ImmutableSetMultimap.Builder()
.putAll(allContributionBindings())
.putAll(allMembersInjectionBindings().entrySet())
.build();
}
/**
* {@code true} if there are no {@link #bindings()} or {@link #multibindingDeclarations()}.
*/
boolean isEmpty() {
return bindings().isEmpty() && multibindingDeclarations().isEmpty();
}
/**
* 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. Empty if this is a members-injection
* binding.
*/
ImmutableSet contributionBindings() {
return ImmutableSet.copyOf(allContributionBindings().values());
}
/**
* The contribution bindings that were resolved in {@link #owningComponent()}. Empty if this is a
* members-injection binding.
*/
ImmutableSet ownedContributionBindings() {
return allContributionBindings().get(owningComponent());
}
/**
* The members-injection binding, regardless of owning component. Empty if these are contribution
* bindings.
*/
Optional membersInjectionBinding() {
ImmutableSet membersInjectionBindings =
FluentIterable.from(allMembersInjectionBindings().values()).toSet();
return membersInjectionBindings.isEmpty()
? Optional.absent()
: Optional.of(Iterables.getOnlyElement(membersInjectionBindings));
}
/**
* The members-injection binding that was resolved in {@link #owningComponent()}. Empty if these
* are contribution bindings.
*/
Optional ownedMembersInjectionBinding() {
return Optional.fromNullable(allMembersInjectionBindings().get(owningComponent()));
}
/**
* Creates a {@link ResolvedBindings} for contribution bindings.
*/
static ResolvedBindings forContributionBindings(
BindingKey bindingKey,
ComponentDescriptor owningComponent,
Multimap contributionBindings,
Iterable multibindings) {
checkArgument(bindingKey.kind().equals(BindingKey.Kind.CONTRIBUTION));
return new AutoValue_ResolvedBindings(
bindingKey,
owningComponent,
ImmutableSetMultimap.copyOf(contributionBindings),
ImmutableMap.of(),
ImmutableSet.copyOf(multibindings));
}
/**
* 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.of(),
ImmutableMap.of(owningComponent, ownedMembersInjectionBinding),
ImmutableSet.of());
}
/**
* 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.of(),
ImmutableMap.of(),
ImmutableSet.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(),
multibindingDeclarations());
}
/**
* {@code true} if this is a multibinding contribution.
*/
boolean isMultibindingContribution() {
return contributionBindings().size() == 1
&& contributionBinding().contributionType().isMultibinding();
}
/**
* {@code true} if this is a {@linkplain ContributionBinding#isSyntheticBinding() synthetic}
* contribution.
*/
boolean isSyntheticContribution() {
return contributionBindings().size() == 1 && contributionBinding().isSyntheticBinding();
}
/**
* Returns the single contribution binding.
*
* @throws IllegalStateException if there is not exactly one element in
* {@link #contributionBindings()}, which will never happen for contributions in valid graphs
*/
ContributionBinding contributionBinding() {
return getOnlyElement(contributionBindings());
}
/**
* The binding type for all {@link #bindings()} and {@link #multibindingDeclarations()}.
*
* @throws IllegalStateException if {@link #isEmpty()} or the binding types conflict
*/
@Override
public BindingType bindingType() {
checkState(!isEmpty(), "empty bindings for %s", bindingKey());
ImmutableSet bindingTypes =
FluentIterable.from(concat(bindings(), multibindingDeclarations()))
.transform(BindingType.BINDING_TYPE)
.toSet();
checkState(bindingTypes.size() == 1, "conflicting binding types: %s", this);
return getOnlyElement(bindingTypes);
}
/**
* The contribution type for these bindings.
*
* @throws IllegalStateException if {@link #isEmpty()} or the contribution types conflict
*/
@Override
public ContributionType contributionType() {
ImmutableSet types = contributionTypes();
checkState(!types.isEmpty(), "no bindings or declarations for %s", bindingKey());
checkState(
types.size() == 1,
"More than one binding present of different types for %s: %s",
bindingKey(),
bindingsAndDeclarationsByContributionType());
return getOnlyElement(types);
}
/**
* The contribution types represented by {@link #contributionBindings()} and
* {@link #multibindingDeclarations()}.
*/
ImmutableSet contributionTypes() {
return bindingsAndDeclarationsByContributionType().keySet();
}
/**
* The {@link #contributionBindings()} and {@link #multibindingDeclarations()}, indexed by
* {@link ContributionType}.
*/
ImmutableListMultimap
bindingsAndDeclarationsByContributionType() {
return new ImmutableListMultimap.Builder()
.putAll(indexByContributionType(contributionBindings()))
.putAll(indexByContributionType(multibindingDeclarations()))
.build();
}
/**
* The name of the package in which these bindings must be managed, for
* example if a binding references non-public types.
*
* @throws IllegalArgumentException if the bindings must be managed in more than one package
*/
Optional bindingPackage() {
ImmutableSet.Builder bindingPackagesBuilder = ImmutableSet.builder();
for (Binding binding : bindings()) {
bindingPackagesBuilder.addAll(binding.bindingPackage().asSet());
}
ImmutableSet bindingPackages = bindingPackagesBuilder.build();
switch (bindingPackages.size()) {
case 0:
return Optional.absent();
case 1:
return Optional.of(bindingPackages.iterator().next());
default:
throw new IllegalArgumentException();
}
}
/**
* The framework class associated with these bindings.
*/
Class> frameworkClass() {
return bindingType().frameworkClass();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy