All Downloads are FREE. Search and download functionalities are using the official Maven repository.

dagger.internal.codegen.ResolvedBindings Maven / Gradle / Ivy

There is a newer version: 2.55
Show newest version
/*
 * 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 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 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