diff --git a/java/dagger/internal/codegen/binding/BindingGraph.java b/java/dagger/internal/codegen/binding/BindingGraph.java index 8dfe74f5f6a..092f8ff9a46 100644 --- a/java/dagger/internal/codegen/binding/BindingGraph.java +++ b/java/dagger/internal/codegen/binding/BindingGraph.java @@ -212,14 +212,7 @@ private static BindingGraph create( // particular BindingNode. Map contributionBindings = new LinkedHashMap<>(); Map membersInjectionBindings = new LinkedHashMap<>(); - - // Construct the maps of the ContributionBindings and MembersInjectionBindings by iterating - // bindings from this component and then from each successive parent. If a binding exists in - // multple components, this order ensures that the child-most binding is always chosen first. - Stream.iterate(componentNode.componentPath(), ComponentPath::parent) - // Stream.iterate is inifinte stream so we need limit it to the known size of the path. - .limit(componentNode.componentPath().components().size()) - .flatMap(path -> topLevelBindingGraph.bindingsByComponent().get(path).stream()) + topLevelBindingGraph.bindingsByComponent().get(componentNode.componentPath()) .forEach( bindingNode -> { if (bindingNode.delegate() instanceof ContributionBinding) { @@ -233,16 +226,19 @@ private static BindingGraph create( BindingGraph bindingGraph = new AutoValue_BindingGraph(componentNode, topLevelBindingGraph); - ImmutableSet modules = - ((ComponentNodeImpl) componentNode).componentDescriptor().modules(); + ImmutableSet modules = + ((ComponentNodeImpl) componentNode).componentDescriptor().modules().stream() + .map(ModuleDescriptor::moduleElement) + .collect(toImmutableSet()); - ImmutableSet inheritedModules = + ImmutableSet inheritedModules = parent.isPresent() ? Sets.union(parent.get().ownedModules, parent.get().inheritedModules).immutableCopy() : ImmutableSet.of(); // Set these fields directly on the instance rather than passing these in as input to the // AutoValue to prevent exposing this data outside of the class. + bindingGraph.parent = parent; bindingGraph.inheritedModules = inheritedModules; bindingGraph.ownedModules = Sets.difference(modules, inheritedModules).immutableCopy(); bindingGraph.contributionBindings = ImmutableMap.copyOf(contributionBindings); @@ -257,10 +253,11 @@ private static BindingGraph create( return bindingGraph; } + private Optional parent; private ImmutableMap contributionBindings; private ImmutableMap membersInjectionBindings; - private ImmutableSet inheritedModules; - private ImmutableSet ownedModules; + private ImmutableSet inheritedModules; + private ImmutableSet ownedModules; private ImmutableSet bindingModules; BindingGraph() {} @@ -287,9 +284,7 @@ public final ComponentDescriptor componentDescriptor() { */ public final Optional localContributionBinding(Key key) { return contributionBindings.containsKey(key) - ? Optional.of(contributionBindings.get(key)) - .filter(bindingNode -> bindingNode.componentPath().equals(componentPath())) - .map(BindingNode::delegate) + ? Optional.of(contributionBindings.get(key).delegate()) : Optional.empty(); } @@ -299,15 +294,18 @@ public final Optional localContributionBinding(Key key) { */ public final Optional localMembersInjectionBinding(Key key) { return membersInjectionBindings.containsKey(key) - ? Optional.of(membersInjectionBindings.get(key)) - .filter(bindingNode -> bindingNode.componentPath().equals(componentPath())) - .map(BindingNode::delegate) + ? Optional.of(membersInjectionBindings.get(key).delegate()) : Optional.empty(); } /** Returns the {@link ContributionBinding} for the given {@link Key}. */ public final ContributionBinding contributionBinding(Key key) { - return (ContributionBinding) contributionBindings.get(key).delegate(); + if (contributionBindings.containsKey(key)) { + return (ContributionBinding) contributionBindings.get(key).delegate(); + } else if (parent.isPresent()) { + return parent.get().contributionBinding(key); + } + throw new AssertionError("Contribution binding not found for key: " + key); } /** @@ -315,9 +313,12 @@ public final ContributionBinding contributionBinding(Key key) { * Optional#empty()} if one does not exist. */ public final Optional membersInjectionBinding(Key key) { - return membersInjectionBindings.containsKey(key) - ? Optional.of((MembersInjectionBinding) membersInjectionBindings.get(key).delegate()) - : Optional.empty(); + if (membersInjectionBindings.containsKey(key)) { + return Optional.of((MembersInjectionBinding) membersInjectionBindings.get(key).delegate()); + } else if (parent.isPresent()) { + return parent.get().membersInjectionBinding(key); + } + return Optional.empty(); } /** Returns the {@link XTypeElement} for the component this graph represents. */ @@ -334,9 +335,7 @@ public final XTypeElement componentTypeElement() { * ancestors. */ public final ImmutableSet ownedModuleTypes() { - return ownedModules.stream() - .map(ModuleDescriptor::moduleElement) - .collect(toImmutableSet()); + return ownedModules; } /** @@ -394,7 +393,7 @@ public ImmutableSet componentRequirements() { ImmutableSet requiredModules = stream(Traverser.forTree(BindingGraph::subgraphs).depthFirstPostOrder(this)) .flatMap(graph -> graph.bindingModules.stream()) - .filter(ownedModuleTypes()::contains) + .filter(ownedModules::contains) .collect(toImmutableSet()); ImmutableSet.Builder requirements = ImmutableSet.builder(); componentDescriptor().requirements().stream() @@ -433,11 +432,18 @@ public ImmutableList localBindingNodes() { return topLevelBindingGraph().bindingsByComponent().get(componentPath()); } - @Memoized + // TODO(bcorso): This method can be costly. Consider removing this method and inlining it into its + // only usage, BindingGraphJsonGenerator. public ImmutableSet bindingNodes() { - return ImmutableSet.builder() - .addAll(contributionBindings.values()) - .addAll(membersInjectionBindings.values()) - .build(); + // Construct the set of bindings by iterating bindings from this component and then from each + // successive parent. If a binding exists in multiple components, this order ensures that the + // child-most binding is always chosen first. + Map bindings = new LinkedHashMap<>(); + Stream.iterate(componentPath(), ComponentPath::parent) + // Stream.iterate() is infinite stream so we need limit it to the known size of the path. + .limit(componentPath().components().size()) + .flatMap(path -> topLevelBindingGraph().bindingsByComponent().get(path).stream()) + .forEach(bindingNode -> bindings.putIfAbsent(bindingNode.key(), bindingNode)); + return ImmutableSet.copyOf(bindings.values()); } }