dagger.model.BindingGraph.java Source code

Java tutorial

Introduction

Here is the source code for dagger.model.BindingGraph.java

Source

/*
 * Copyright (C) 2016 The Dagger Authors.
 *
 * 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.model;

import static com.google.common.base.Verify.verify;
import static com.google.common.collect.Sets.intersection;
import static com.google.common.graph.Graphs.inducedSubgraph;
import static com.google.common.graph.Graphs.reachableNodes;
import static com.google.common.graph.Graphs.transpose;
import static dagger.internal.codegen.DaggerStreams.instancesOf;
import static dagger.internal.codegen.DaggerStreams.toImmutableSet;
import static dagger.internal.codegen.DaggerStreams.toImmutableSetMultimap;

import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.graph.EndpointPair;
import com.google.common.graph.ImmutableNetwork;
import com.google.common.graph.MutableNetwork;
import com.google.common.graph.Network;
import com.google.common.graph.NetworkBuilder;
import dagger.Module;
import java.util.Optional;
import java.util.stream.Stream;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;

/**
 * A graph of bindings, dependency requests, and components.
 *
 * <p>A {@link BindingGraph} represents one of the following:
 *
 * <ul>
 *   <li>an entire component hierarchy rooted at a {@link dagger.Component} or {@link
 *       dagger.producers.ProductionComponent}
 *   <li>a partial component hierarchy rooted at a {@link dagger.Subcomponent} or {@link
 *       dagger.producers.ProductionSubcomponent} (only when {@code
 *       -Adagger.experimentalAheadOfTimeSubcomponents=enabled} is passed to the compiler)
 *   <li>the bindings installed by a {@link Module} or {@link dagger.producers.ProducerModule},
 *       including all subcomponents generated by {@link Module#subcomponents()} ()} and {@link
 *       dagger.producers.ProducerModule#subcomponents()} ()}
 * </ul>
 *
 * In the case of a {@link BindingGraph} representing a module, the root {@link ComponentNode} will
 * actually represent the module type, and there will be an entry point edge (with no request
 * element) for every binding (except multibinding contributions) in the module, including its
 * transitively included modules.
 *
 * <h3>Nodes</h3>
 *
 * <p>There is a <b>{@link Binding}</b> for each owned binding in the graph. If a binding is owned
 * by more than one component, there is one binding object for that binding for every owning
 * component.
 *
 * <p>There is a <b>{@linkplain ComponentNode component node}</b> (without a binding) for each
 * component in the graph.
 *
 * <h3>Edges</h3>
 *
 * <p>There is a <b>{@linkplain DependencyEdge dependency edge}</b> for each dependency request in
 * the graph. Its target node is the binding for the binding that satisfies the request. For entry
 * point dependency requests, the source node is the component node for the component for which it
 * is an entry point. For other dependency requests, the source node is the binding for the binding
 * that contains the request.
 *
 * <p>There is a <b>subcomponent edge</b> for each parent-child component relationship in the graph.
 * The target node is the component node for the child component. For subcomponents defined by a
 * {@linkplain SubcomponentBuilderBindingEdge subcomponent builder binding} (either a method on the
 * component or a set of {@code @Module.subcomponents} annotation values), the source node is the
 * binding for the {@code @Subcomponent.Builder} type. For subcomponents defined by {@linkplain
 * ChildFactoryMethodEdge subcomponent factory methods}, the source node is the component node for
 * the parent.
 *
 * <p><b>Note that this API is experimental and will change.</b>
 */
@AutoValue
public abstract class BindingGraph {

    static BindingGraph create(Network<Node, Edge> network, boolean isModuleBindingGraph,
            boolean isPartialBindingGraph) {
        return new AutoValue_BindingGraph(ImmutableNetwork.copyOf(network), isModuleBindingGraph,
                isPartialBindingGraph);
    }

    BindingGraph() {
    }

    /** Returns the graph in its {@link Network} representation. */
    public abstract ImmutableNetwork<Node, Edge> network();

    @Override
    public final String toString() {
        return network().toString();
    }

    /**
     * Returns{@code true} if this graph was constructed from a module for module binding validation.
     *
     * @see <a href="https://google.github.io/dagger/compiler-options#module-binding-validation">Module binding
     *     validation</a>
     */
    // TODO(dpb): Figure out the relationship between this and isPartialBindingGraph(). Maybe this
    // implies that?
    public abstract boolean isModuleBindingGraph();

    /**
     * Returns {@code true} if this graph was constructed with a root subcomponent in ahead-of-time
     * subcomponents mode.
     */
    public abstract boolean isPartialBindingGraph();

    /** Returns the bindings. */
    public final ImmutableSet<Binding> bindings() {
        return nodes(Binding.class);
    }

    /** Returns the bindings for a key. */
    public final ImmutableSet<Binding> bindings(Key key) {
        return nodeStream(Binding.class).filter(binding -> binding.key().equals(key)).collect(toImmutableSet());
    }

    /** Returns the nodes that represent missing bindings. */
    public final ImmutableSet<MissingBinding> missingBindings() {
        return nodes(MissingBinding.class);
    }

    /** Returns the component nodes. */
    public final ImmutableSet<ComponentNode> componentNodes() {
        return nodes(ComponentNode.class);
    }

    /** Returns the component node for a component. */
    public final Optional<ComponentNode> componentNode(ComponentPath component) {
        return nodeStream(ComponentNode.class).filter(node -> node.componentPath().equals(component)).findFirst();
    }

    /** Returns the component nodes for a component. */
    public final ImmutableSet<ComponentNode> componentNodes(TypeElement component) {
        return nodeStream(ComponentNode.class)
                .filter(node -> node.componentPath().currentComponent().equals(component))
                .collect(toImmutableSet());
    }

    /** Returns the component node for the root component. */
    public final ComponentNode rootComponentNode() {
        return nodeStream(ComponentNode.class).filter(node -> node.componentPath().atRoot()).findFirst().get();
    }

    /** Returns the dependency edges. */
    public final ImmutableSet<DependencyEdge> dependencyEdges() {
        return dependencyEdgeStream().collect(toImmutableSet());
    }

    /**
     * Returns the dependency edges for the dependencies of a binding. For valid graphs, each {@link
     * DependencyRequest} will map to a single {@link DependencyEdge}. When conflicting bindings exist
     * for a key, the multimap will have several edges for that {@link DependencyRequest}. Graphs that
     * have no binding for a key will have an edge whose {@linkplain EndpointPair#target() target
     * node} is a {@link MissingBinding}.
     */
    public final ImmutableSetMultimap<DependencyRequest, DependencyEdge> dependencyEdges(Binding binding) {
        return dependencyEdgeStream(binding)
                .collect(toImmutableSetMultimap(DependencyEdge::dependencyRequest, edge -> edge));
    }

    /** Returns the dependency edges for a dependency request. */
    public final ImmutableSet<DependencyEdge> dependencyEdges(DependencyRequest dependencyRequest) {
        return dependencyEdgeStream().filter(edge -> edge.dependencyRequest().equals(dependencyRequest))
                .collect(toImmutableSet());
    }

    /**
     * Returns the dependency edges for the entry points of a given {@code component}. Each edge's
     * source node is that component's component node.
     */
    public final ImmutableSet<DependencyEdge> entryPointEdges(ComponentPath component) {
        return dependencyEdgeStream(componentNode(component).get()).collect(toImmutableSet());
    }

    private Stream<DependencyEdge> dependencyEdgeStream(Node node) {
        return network().outEdges(node).stream().flatMap(instancesOf(DependencyEdge.class));
    }

    /**
     * Returns the dependency edges for all entry points for all components and subcomponents. Each
     * edge's source node is a component node.
     */
    public final ImmutableSet<DependencyEdge> entryPointEdges() {
        return entryPointEdgeStream().collect(toImmutableSet());
    }

    /** Returns the binding or missing binding nodes that directly satisfy entry points. */
    public final ImmutableSet<MaybeBinding> entryPointBindings() {
        return entryPointEdgeStream().map(edge -> (MaybeBinding) network().incidentNodes(edge).target())
                .collect(toImmutableSet());
    }

    /**
     * Returns the edges for entry points that transitively depend on a binding or missing binding for
     * a key. Never returns an empty set.
     */
    public final ImmutableSet<DependencyEdge> entryPointEdgesDependingOnBinding(MaybeBinding binding) {
        ImmutableNetwork<Node, DependencyEdge> dependencyGraph = dependencyGraph();
        Network<Node, DependencyEdge> subgraphDependingOnBinding = inducedSubgraph(dependencyGraph,
                reachableNodes(transpose(dependencyGraph).asGraph(), binding));
        ImmutableSet<DependencyEdge> entryPointEdges = intersection(entryPointEdges(),
                subgraphDependingOnBinding.edges()).immutableCopy();
        verify(!entryPointEdges.isEmpty(), "No entry points depend on binding %s", binding);
        return entryPointEdges;
    }

    /** Returns the bindings that directly request a given binding as a dependency. */
    public final ImmutableSet<Binding> requestingBindings(MaybeBinding binding) {
        return network().predecessors(binding).stream().flatMap(instancesOf(Binding.class))
                .collect(toImmutableSet());
    }

    /**
     * Returns the bindings that a given binding directly request as a dependency. Does not include
     * any {@link MissingBinding}s.
     *
     * @see #requestedMaybeMissingBindings(Binding)
     */
    public final ImmutableSet<Binding> requestedBindings(Binding binding) {
        return network().successors(binding).stream().flatMap(instancesOf(Binding.class)).collect(toImmutableSet());
    }

    /**
     * Returns the bindings or missing bindings that a given binding directly requests as a
     * dependency.
     *
     * @see #requestedBindings(Binding)
     */
    public final ImmutableSet<MaybeBinding> requestedMaybeMissingBindings(Binding binding) {
        return network().successors(binding).stream().flatMap(instancesOf(MaybeBinding.class))
                .collect(toImmutableSet());
    }

    // TODO(dpb): Make public. Cache.
    private ImmutableNetwork<Node, DependencyEdge> dependencyGraph() {
        MutableNetwork<Node, DependencyEdge> dependencyGraph = NetworkBuilder.from(network())
                .expectedNodeCount(network().nodes().size()).expectedEdgeCount((int) dependencyEdgeStream().count())
                .build();
        dependencyEdgeStream().forEach(edge -> {
            EndpointPair<Node> endpoints = network().incidentNodes(edge);
            dependencyGraph.addEdge(endpoints.source(), endpoints.target(), edge);
        });
        return ImmutableNetwork.copyOf(dependencyGraph);
    }

    private <N extends Node> ImmutableSet<N> nodes(Class<N> clazz) {
        return nodeStream(clazz).collect(toImmutableSet());
    }

    private <N extends Node> Stream<N> nodeStream(Class<N> clazz) {
        return network().nodes().stream().flatMap(instancesOf(clazz));
    }

    private Stream<DependencyEdge> dependencyEdgeStream() {
        return network().edges().stream().flatMap(instancesOf(DependencyEdge.class));
    }

    private Stream<DependencyEdge> entryPointEdgeStream() {
        return dependencyEdgeStream().filter(DependencyEdge::isEntryPoint);
    }

    /**
     * An edge in the binding graph. Either a {@link DependencyEdge}, a {@link
     * ChildFactoryMethodEdge}, or a {@link SubcomponentBuilderBindingEdge}.
     */
    public interface Edge {
    }

    /**
     * An edge that represents a dependency on a binding.
     *
     * <p>Because one {@link DependencyRequest} may represent a dependency from two bindings (e.g., a
     * dependency of {@code Foo<String>} and {@code Foo<Number>} may have the same key and request
     * element), this class does not override {@link #equals(Object)} to use value semantics.
     *
     * <p>For entry points, the source node is the {@link ComponentNode} that contains the entry
     * point. Otherwise the source node is a {@link Binding}.
     *
     * <p>For dependencies on missing bindings, the target node is a {@link MissingBinding}. Otherwise
     * the target node is a {@link Binding}.
     */
    public interface DependencyEdge extends Edge {
        /** The dependency request. */
        DependencyRequest dependencyRequest();

        /** Returns {@code true} if this edge represents an entry point. */
        boolean isEntryPoint();
    }

    /**
     * An edge that represents a subcomponent factory method linking a parent component to a child
     * subcomponent.
     */
    public interface ChildFactoryMethodEdge extends Edge {
        /** The subcomponent factory method element. */
        ExecutableElement factoryMethod();
    }

    /**
     * An edge that represents the link between a parent component and a child subcomponent implied by
     * a subcomponent builder binding. The {@linkplain com.google.common.graph.EndpointPair#source()
     * source node} of this edge is a {@link Binding} for the subcomponent builder {@link Key} and the
     * {@linkplain com.google.common.graph.EndpointPair#target() target node} is a {@link
     * ComponentNode} for the child subcomponent.
     */
    public interface SubcomponentBuilderBindingEdge extends Edge {
        /**
         * The modules that {@linkplain Module#subcomponents() declare the subcomponent} that generated
         * this edge. Empty if the parent component has a subcomponent builder method and there are no
         * declaring modules.
         */
        ImmutableSet<TypeElement> declaringModules();
    }

    /** A node in the binding graph. Either a {@link Binding} or a {@link ComponentNode}. */
    // TODO(dpb): Make all the node/edge types top-level.
    public interface Node {
        /** The component this node belongs to. */
        ComponentPath componentPath();
    }

    /** A node in the binding graph that is either a {@link Binding} or a {@link MissingBinding}. */
    public interface MaybeBinding extends Node {

        /** The component that owns the binding, or in which the binding is missing. */
        @Override
        ComponentPath componentPath();

        /** The key of the binding, or for which there is no binding. */
        Key key();

        /** The binding, or empty if missing. */
        Optional<Binding> binding();
    }

    /** A node in the binding graph that represents a missing binding for a key in a component. */
    @AutoValue
    public abstract static class MissingBinding implements MaybeBinding {
        static MissingBinding create(ComponentPath component, Key key) {
            return new AutoValue_BindingGraph_MissingBinding(component, key);
        }

        /** The component in which the binding is missing. */
        @Override
        public abstract ComponentPath componentPath();

        /** The key for which there is no binding. */
        public abstract Key key();

        /** @deprecated This always returns {@code Optional.empty()}. */
        @Override
        @Deprecated
        public final Optional<Binding> binding() {
            return Optional.empty();
        }

        @Override
        public final String toString() {
            return String.format("missing binding for %s in %s", key(), componentPath());
        }
    }

    /**
     * A <b>component node</b> in the graph. Every entry point {@linkplain DependencyEdge dependency
     * edge}'s source node is a component node for the component containing the entry point.
     */
    public interface ComponentNode extends Node {

        /** The component represented by this node. */
        @Override
        ComponentPath componentPath();

        /** The entry points on this component. */
        ImmutableSet<DependencyRequest> entryPoints();

        /** The scopes declared on this component. */
        ImmutableSet<Scope> scopes();
    }
}