1 /* 2 * Copyright (C) 2014 Google, Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package dagger.internal.codegen; 17 18 import com.google.auto.common.MoreTypes; 19 import com.google.auto.value.AutoValue; 20 import com.google.common.base.Function; 21 import com.google.common.base.Optional; 22 import com.google.common.cache.Cache; 23 import com.google.common.cache.CacheBuilder; 24 import com.google.common.collect.FluentIterable; 25 import com.google.common.collect.ImmutableList; 26 import com.google.common.collect.ImmutableMap; 27 import com.google.common.collect.ImmutableSet; 28 import com.google.common.collect.ImmutableSetMultimap; 29 import com.google.common.collect.Iterables; 30 import com.google.common.collect.Lists; 31 import com.google.common.collect.Maps; 32 import com.google.common.collect.Sets; 33 import com.google.common.collect.TreeTraverser; 34 import dagger.Component; 35 import dagger.Subcomponent; 36 import dagger.internal.codegen.Binding.Type; 37 import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor; 38 import dagger.producers.Producer; 39 import dagger.producers.ProductionComponent; 40 import java.util.ArrayDeque; 41 import java.util.Collection; 42 import java.util.Deque; 43 import java.util.HashSet; 44 import java.util.List; 45 import java.util.Map; 46 import java.util.Map.Entry; 47 import java.util.Set; 48 import java.util.concurrent.Callable; 49 import java.util.concurrent.ExecutionException; 50 import java.util.concurrent.Executor; 51 import javax.inject.Inject; 52 import javax.lang.model.element.AnnotationMirror; 53 import javax.lang.model.element.ExecutableElement; 54 import javax.lang.model.element.TypeElement; 55 import javax.lang.model.util.ElementFilter; 56 import javax.lang.model.util.Elements; 57 58 import static com.google.auto.common.MoreElements.getAnnotationMirror; 59 import static com.google.common.base.Predicates.in; 60 import static com.google.common.base.Verify.verify; 61 import static com.google.common.collect.Iterables.any; 62 import static com.google.common.collect.Sets.union; 63 import static dagger.internal.codegen.BindingKey.Kind.CONTRIBUTION; 64 import static dagger.internal.codegen.ComponentDescriptor.isComponentContributionMethod; 65 import static dagger.internal.codegen.ComponentDescriptor.isComponentProductionMethod; 66 import static dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor.isOfKind; 67 import static dagger.internal.codegen.ComponentDescriptor.ComponentMethodKind.SUBCOMPONENT_BUILDER; 68 import static dagger.internal.codegen.ComponentDescriptor.Kind.PRODUCTION_COMPONENT; 69 import static dagger.internal.codegen.ConfigurationAnnotations.getComponentDependencies; 70 import static dagger.internal.codegen.MembersInjectionBinding.Strategy.INJECT_MEMBERS; 71 import static dagger.internal.codegen.MembersInjectionBinding.Strategy.NO_OP; 72 import static javax.lang.model.element.Modifier.STATIC; 73 74 /** 75 * The canonical representation of a full-resolved graph. 76 * 77 * @author Gregory Kick 78 */ 79 @AutoValue 80 abstract class BindingGraph { componentDescriptor()81 abstract ComponentDescriptor componentDescriptor(); resolvedBindings()82 abstract ImmutableMap<BindingKey, ResolvedBindings> resolvedBindings(); subgraphs()83 abstract ImmutableMap<ExecutableElement, BindingGraph> subgraphs(); 84 85 /** 86 * Returns the set of modules that are owned by this graph regardless of whether or not any of 87 * their bindings are used in this graph. For graphs representing top-level {@link Component 88 * components}, this set will be the same as 89 * {@linkplain ComponentDescriptor#transitiveModules the component's transitive modules}. For 90 * {@linkplain Subcomponent subcomponents}, this set will be the transitive modules that are not 91 * owned by any of their ancestors. 92 */ ownedModules()93 abstract ImmutableSet<ModuleDescriptor> ownedModules(); 94 ownedModuleTypes()95 ImmutableSet<TypeElement> ownedModuleTypes() { 96 return FluentIterable.from(ownedModules()) 97 .transform(ModuleDescriptor.getModuleElement()) 98 .toSet(); 99 } 100 101 private static final TreeTraverser<BindingGraph> SUBGRAPH_TRAVERSER = 102 new TreeTraverser<BindingGraph>() { 103 @Override 104 public Iterable<BindingGraph> children(BindingGraph node) { 105 return node.subgraphs().values(); 106 } 107 }; 108 109 /** 110 * Returns the set of types necessary to implement the component, but are not part of the injected 111 * graph. This includes modules, component dependencies and an {@link Executor} in the case of 112 * {@link ProductionComponent}. 113 */ componentRequirements()114 ImmutableSet<TypeElement> componentRequirements() { 115 return SUBGRAPH_TRAVERSER 116 .preOrderTraversal(this) 117 .transformAndConcat( 118 new Function<BindingGraph, Iterable<ResolvedBindings>>() { 119 @Override 120 public Iterable<ResolvedBindings> apply(BindingGraph input) { 121 return input.resolvedBindings().values(); 122 } 123 }) 124 .transformAndConcat( 125 new Function<ResolvedBindings, Set<ContributionBinding>>() { 126 @Override 127 public Set<ContributionBinding> apply(ResolvedBindings input) { 128 return (input.bindingKey().kind().equals(CONTRIBUTION)) 129 ? input.contributionBindings() 130 : ImmutableSet.<ContributionBinding>of(); 131 } 132 }) 133 .transformAndConcat( 134 new Function<ContributionBinding, Set<TypeElement>>() { 135 @Override 136 public Set<TypeElement> apply(ContributionBinding input) { 137 return input.bindingElement().getModifiers().contains(STATIC) 138 ? ImmutableSet.<TypeElement>of() 139 : input.contributedBy().asSet(); 140 } 141 }) 142 .filter(in(ownedModuleTypes())) 143 .append(componentDescriptor().dependencies()) 144 .append(componentDescriptor().executorDependency().asSet()) 145 .toSet(); 146 } 147 148 ImmutableSet<TypeElement> availableDependencies() { 149 return new ImmutableSet.Builder<TypeElement>() 150 .addAll(componentDescriptor().transitiveModuleTypes()) 151 .addAll(componentDescriptor().dependencies()) 152 .addAll(componentDescriptor().executorDependency().asSet()) 153 .build(); 154 } 155 156 static final class Factory { 157 private final Elements elements; 158 private final InjectBindingRegistry injectBindingRegistry; 159 private final Key.Factory keyFactory; 160 private final ProvisionBinding.Factory provisionBindingFactory; 161 private final ProductionBinding.Factory productionBindingFactory; 162 163 Factory(Elements elements, 164 InjectBindingRegistry injectBindingRegistry, 165 Key.Factory keyFactory, 166 ProvisionBinding.Factory provisionBindingFactory, 167 ProductionBinding.Factory productionBindingFactory) { 168 this.elements = elements; 169 this.injectBindingRegistry = injectBindingRegistry; 170 this.keyFactory = keyFactory; 171 this.provisionBindingFactory = provisionBindingFactory; 172 this.productionBindingFactory = productionBindingFactory; 173 } 174 175 BindingGraph create(ComponentDescriptor componentDescriptor) { 176 return create(Optional.<Resolver>absent(), componentDescriptor); 177 } 178 179 private BindingGraph create( 180 Optional<Resolver> parentResolver, ComponentDescriptor componentDescriptor) { 181 ImmutableSet.Builder<ContributionBinding> explicitBindingsBuilder = ImmutableSet.builder(); 182 183 // binding for the component itself 184 TypeElement componentDefinitionType = componentDescriptor.componentDefinitionType(); 185 explicitBindingsBuilder.add(provisionBindingFactory.forComponent(componentDefinitionType)); 186 187 // Collect Component dependencies. 188 Optional<AnnotationMirror> componentMirror = 189 getAnnotationMirror(componentDefinitionType, Component.class) 190 .or(getAnnotationMirror(componentDefinitionType, ProductionComponent.class)); 191 ImmutableSet<TypeElement> componentDependencyTypes = componentMirror.isPresent() 192 ? MoreTypes.asTypeElements(getComponentDependencies(componentMirror.get())) 193 : ImmutableSet.<TypeElement>of(); 194 for (TypeElement componentDependency : componentDependencyTypes) { 195 explicitBindingsBuilder.add(provisionBindingFactory.forComponent(componentDependency)); 196 List<ExecutableElement> dependencyMethods = 197 ElementFilter.methodsIn(elements.getAllMembers(componentDependency)); 198 for (ExecutableElement method : dependencyMethods) { 199 // MembersInjection methods aren't "provided" explicitly, so ignore them. 200 if (isComponentContributionMethod(elements, method)) { 201 explicitBindingsBuilder.add( 202 componentDescriptor.kind().equals(PRODUCTION_COMPONENT) 203 && isComponentProductionMethod(elements, method) 204 ? productionBindingFactory.forComponentMethod(method) 205 : provisionBindingFactory.forComponentMethod(method)); 206 } 207 } 208 } 209 210 // Bindings for subcomponent builders. 211 for (ComponentMethodDescriptor subcomponentMethodDescriptor : 212 Iterables.filter( 213 componentDescriptor.subcomponents().keySet(), isOfKind(SUBCOMPONENT_BUILDER))) { 214 explicitBindingsBuilder.add( 215 provisionBindingFactory.forSubcomponentBuilderMethod( 216 subcomponentMethodDescriptor.methodElement(), 217 componentDescriptor.componentDefinitionType())); 218 } 219 220 // Collect transitive module bindings. 221 for (ModuleDescriptor moduleDescriptor : componentDescriptor.transitiveModules()) { 222 for (ContributionBinding binding : moduleDescriptor.bindings()) { 223 explicitBindingsBuilder.add(binding); 224 } 225 } 226 227 Resolver requestResolver = 228 new Resolver( 229 parentResolver, 230 componentDescriptor, 231 explicitBindingsByKey(explicitBindingsBuilder.build())); 232 for (ComponentMethodDescriptor componentMethod : componentDescriptor.componentMethods()) { 233 Optional<DependencyRequest> componentMethodRequest = componentMethod.dependencyRequest(); 234 if (componentMethodRequest.isPresent()) { 235 requestResolver.resolve(componentMethodRequest.get()); 236 } 237 } 238 239 ImmutableMap.Builder<ExecutableElement, BindingGraph> subgraphsBuilder = 240 ImmutableMap.builder(); 241 for (Entry<ComponentMethodDescriptor, ComponentDescriptor> subcomponentEntry : 242 componentDescriptor.subcomponents().entrySet()) { 243 subgraphsBuilder.put( 244 subcomponentEntry.getKey().methodElement(), 245 create(Optional.of(requestResolver), subcomponentEntry.getValue())); 246 } 247 248 for (ResolvedBindings resolvedBindings : requestResolver.getResolvedBindings().values()) { 249 verify( 250 resolvedBindings.owningComponent().equals(componentDescriptor), 251 "%s is not owned by %s", 252 resolvedBindings, 253 componentDescriptor); 254 } 255 256 return new AutoValue_BindingGraph( 257 componentDescriptor, 258 requestResolver.getResolvedBindings(), 259 subgraphsBuilder.build(), 260 requestResolver.getOwnedModules()); 261 } 262 263 private <B extends ContributionBinding> ImmutableSetMultimap<Key, B> explicitBindingsByKey( 264 Iterable<? extends B> bindings) { 265 // Multimaps.index() doesn't do ImmutableSetMultimaps. 266 ImmutableSetMultimap.Builder<Key, B> builder = ImmutableSetMultimap.builder(); 267 for (B binding : bindings) { 268 builder.put(binding.key(), binding); 269 } 270 return builder.build(); 271 } 272 273 private final class Resolver { 274 final Optional<Resolver> parentResolver; 275 final ComponentDescriptor componentDescriptor; 276 final ImmutableSetMultimap<Key, ContributionBinding> explicitBindings; 277 final ImmutableSet<ContributionBinding> explicitBindingsSet; 278 final Map<BindingKey, ResolvedBindings> resolvedBindings; 279 final Deque<BindingKey> cycleStack = new ArrayDeque<>(); 280 final Cache<BindingKey, Boolean> dependsOnLocalMultibindingsCache = 281 CacheBuilder.newBuilder().<BindingKey, Boolean>build(); 282 283 Resolver( 284 Optional<Resolver> parentResolver, 285 ComponentDescriptor componentDescriptor, 286 ImmutableSetMultimap<Key, ContributionBinding> explicitBindings) { 287 assert parentResolver != null; 288 this.parentResolver = parentResolver; 289 assert componentDescriptor != null; 290 this.componentDescriptor = componentDescriptor; 291 assert explicitBindings != null; 292 this.explicitBindings = explicitBindings; 293 this.explicitBindingsSet = ImmutableSet.copyOf(explicitBindings.values()); 294 this.resolvedBindings = Maps.newLinkedHashMap(); 295 } 296 297 /** 298 * Looks up the bindings associated with a given dependency request and returns them. 299 * 300 * <p>Requests for {@code Map<K, V>} for which there are only bindings for 301 * {@code Map<K, Provider<V>>} will resolve to a single implicit binding for the latter map 302 * (and similarly for {@link Producer}s). 303 * 304 * <p>If there are no explicit bindings for a contribution, looks for implicit 305 * {@link Inject @Inject}-annotated constructor types. 306 */ 307 ResolvedBindings lookUpBindings(DependencyRequest request) { 308 BindingKey bindingKey = request.bindingKey(); 309 switch (bindingKey.kind()) { 310 case CONTRIBUTION: 311 // First, check for explicit keys (those from modules and components) 312 ImmutableSet<ContributionBinding> explicitBindingsForKey = 313 getExplicitBindings(bindingKey.key()); 314 315 // If the key is Map<K, V>, get its implicit binding keys, which are either 316 // Map<K, Provider<V>> or Map<K, Producer<V>>, and grab their explicit bindings. 317 Optional<Key> mapProviderKey = keyFactory.implicitMapProviderKeyFrom(bindingKey.key()); 318 ImmutableSet.Builder<ContributionBinding> explicitMapBindingsBuilder = 319 ImmutableSet.builder(); 320 if (mapProviderKey.isPresent()) { 321 explicitMapBindingsBuilder.addAll(getExplicitBindings(mapProviderKey.get())); 322 } 323 324 Optional<Key> mapProducerKey = keyFactory.implicitMapProducerKeyFrom(bindingKey.key()); 325 if (mapProducerKey.isPresent()) { 326 explicitMapBindingsBuilder.addAll(getExplicitBindings(mapProducerKey.get())); 327 } 328 ImmutableSet<ContributionBinding> explicitMapBindings = 329 explicitMapBindingsBuilder.build(); 330 331 // If the key is Set<Produced<T>>, then we look up bindings by the alternate key Set<T>. 332 Optional<Key> setKeyFromProduced = 333 keyFactory.implicitSetKeyFromProduced(bindingKey.key()); 334 ImmutableSet<ContributionBinding> explicitSetBindings = 335 setKeyFromProduced.isPresent() 336 ? getExplicitBindings(setKeyFromProduced.get()) 337 : ImmutableSet.<ContributionBinding>of(); 338 339 if (!explicitBindingsForKey.isEmpty() || !explicitSetBindings.isEmpty()) { 340 /* If there are any explicit bindings for this key, then combine those with any 341 * conflicting Map<K, Provider<V>> bindings and let the validator fail. */ 342 ImmutableSetMultimap.Builder<ComponentDescriptor, ContributionBinding> bindings = 343 ImmutableSetMultimap.builder(); 344 for (ContributionBinding binding : 345 union(explicitBindingsForKey, union(explicitSetBindings, explicitMapBindings))) { 346 bindings.put(getOwningComponent(request, binding), binding); 347 } 348 return ResolvedBindings.forContributionBindings( 349 bindingKey, componentDescriptor, bindings.build()); 350 } else if (any(explicitMapBindings, Binding.Type.PRODUCTION)) { 351 /* If this binding is for Map<K, V> and there are no explicit Map<K, V> bindings but 352 * some explicit Map<K, Producer<V>> bindings, then this binding must have only the 353 * implicit dependency on Map<K, Producer<V>>. */ 354 return ResolvedBindings.forContributionBindings( 355 bindingKey, 356 componentDescriptor, 357 productionBindingFactory.implicitMapOfProducerBinding(request)); 358 } else if (any(explicitMapBindings, Binding.Type.PROVISION)) { 359 /* If this binding is for Map<K, V> and there are no explicit Map<K, V> bindings but 360 * some explicit Map<K, Provider<V>> bindings, then this binding must have only the 361 * implicit dependency on Map<K, Provider<V>>. */ 362 return ResolvedBindings.forContributionBindings( 363 bindingKey, 364 componentDescriptor, 365 provisionBindingFactory.implicitMapOfProviderBinding(request)); 366 } else { 367 /* If there are no explicit bindings at all, look for an implicit @Inject-constructed 368 * binding. */ 369 Optional<ProvisionBinding> provisionBinding = 370 injectBindingRegistry.getOrFindProvisionBinding(bindingKey.key()); 371 ComponentDescriptor owningComponent = 372 provisionBinding.isPresent() 373 && isResolvedInParent(request, provisionBinding.get()) 374 && !shouldOwnParentBinding(request, provisionBinding.get()) 375 ? getOwningResolver(provisionBinding.get()).get().componentDescriptor 376 : componentDescriptor; 377 return ResolvedBindings.forContributionBindings( 378 bindingKey, 379 componentDescriptor, 380 ImmutableSetMultimap.<ComponentDescriptor, ContributionBinding>builder() 381 .putAll(owningComponent, provisionBinding.asSet()) 382 .build()); 383 } 384 385 case MEMBERS_INJECTION: 386 // no explicit deps for members injection, so just look it up 387 return ResolvedBindings.forMembersInjectionBinding( 388 bindingKey, componentDescriptor, rollUpMembersInjectionBindings(bindingKey.key())); 389 default: 390 throw new AssertionError(); 391 } 392 } 393 394 /** 395 * If {@code binding} should be owned by a parent component, resolves the binding in that 396 * component's resolver and returns that component. Otherwise returns the component for this 397 * resolver. 398 */ 399 private ComponentDescriptor getOwningComponent( 400 DependencyRequest request, ContributionBinding binding) { 401 return isResolvedInParent(request, binding) && !shouldOwnParentBinding(request, binding) 402 ? getOwningResolver(binding).get().componentDescriptor 403 : componentDescriptor; 404 } 405 406 /** 407 * Returns {@code true} if {@code binding} is owned by a parent resolver. If so, calls 408 * {@link #resolve(DependencyRequest) resolve(request)} on that resolver. 409 */ 410 private boolean isResolvedInParent(DependencyRequest request, ContributionBinding binding) { 411 Optional<Resolver> owningResolver = getOwningResolver(binding); 412 if (owningResolver.isPresent() && !owningResolver.get().equals(this)) { 413 owningResolver.get().resolve(request); 414 return true; 415 } else { 416 return false; 417 } 418 } 419 420 /** 421 * Returns {@code true} if {@code binding}, which was previously resolved by a parent 422 * resolver, should be moved into this resolver's bindings for {@code request} because it is 423 * unscoped and {@linkplain #dependsOnLocalMultibindings(ResolvedBindings) depends on local 424 * multibindings}, or {@code false} if it can satisfy {@code request} as an inherited binding. 425 */ 426 private boolean shouldOwnParentBinding( 427 DependencyRequest request, ContributionBinding binding) { 428 return !binding.scope().isPresent() 429 && dependsOnLocalMultibindings( 430 getPreviouslyResolvedBindings(request.bindingKey()).get()); 431 } 432 433 private MembersInjectionBinding rollUpMembersInjectionBindings(Key key) { 434 MembersInjectionBinding membersInjectionBinding = 435 injectBindingRegistry.getOrFindMembersInjectionBinding(key); 436 437 if (membersInjectionBinding.parentInjectorRequest().isPresent() 438 && membersInjectionBinding.injectionStrategy().equals(INJECT_MEMBERS)) { 439 MembersInjectionBinding parentBinding = 440 rollUpMembersInjectionBindings( 441 membersInjectionBinding.parentInjectorRequest().get().key()); 442 if (parentBinding.injectionStrategy().equals(NO_OP)) { 443 return membersInjectionBinding.withoutParentInjectorRequest(); 444 } 445 } 446 447 return membersInjectionBinding; 448 } 449 450 private Optional<Resolver> getOwningResolver(ContributionBinding provisionBinding) { 451 for (Resolver requestResolver : getResolverLineage().reverse()) { 452 if (requestResolver.explicitBindingsSet.contains(provisionBinding)) { 453 return Optional.of(requestResolver); 454 } 455 } 456 457 // look for scope separately. we do this for the case where @Singleton can appear twice 458 // in the † compatibility mode 459 Scope bindingScope = provisionBinding.scope(); 460 if (bindingScope.isPresent()) { 461 for (Resolver requestResolver : getResolverLineage().reverse()) { 462 if (bindingScope.equals(requestResolver.componentDescriptor.scope())) { 463 return Optional.of(requestResolver); 464 } 465 } 466 } 467 return Optional.absent(); 468 } 469 470 /** Returns the resolver lineage from parent to child. */ 471 private ImmutableList<Resolver> getResolverLineage() { 472 List<Resolver> resolverList = Lists.newArrayList(); 473 for (Optional<Resolver> currentResolver = Optional.of(this); 474 currentResolver.isPresent(); 475 currentResolver = currentResolver.get().parentResolver) { 476 resolverList.add(currentResolver.get()); 477 } 478 return ImmutableList.copyOf(Lists.reverse(resolverList)); 479 } 480 481 private ImmutableSet<ContributionBinding> getExplicitBindings(Key requestKey) { 482 ImmutableSet.Builder<ContributionBinding> explicitBindingsForKey = ImmutableSet.builder(); 483 for (Resolver resolver : getResolverLineage()) { 484 explicitBindingsForKey.addAll(resolver.explicitBindings.get(requestKey)); 485 } 486 return explicitBindingsForKey.build(); 487 } 488 489 private Optional<ResolvedBindings> getPreviouslyResolvedBindings( 490 final BindingKey bindingKey) { 491 Optional<ResolvedBindings> result = Optional.fromNullable(resolvedBindings.get(bindingKey)); 492 if (result.isPresent()) { 493 return result; 494 } else if (parentResolver.isPresent()) { 495 return parentResolver.get().getPreviouslyResolvedBindings(bindingKey); 496 } else { 497 return Optional.absent(); 498 } 499 } 500 501 void resolve(DependencyRequest request) { 502 BindingKey bindingKey = request.bindingKey(); 503 504 // If we find a cycle, stop resolving. The original request will add it with all of the 505 // other resolved deps. 506 if (cycleStack.contains(bindingKey)) { 507 return; 508 } 509 510 // If the binding was previously resolved in this (sub)component, don't resolve it again. 511 if (resolvedBindings.containsKey(bindingKey)) { 512 return; 513 } 514 515 // If the binding was previously resolved in a supercomponent, then test to see if it 516 // depends on multibindings with contributions from this subcomponent. If it does, then we 517 // have to resolve it in this subcomponent so that it sees the local contributions. If it 518 // does not, then we can stop resolving it in this subcomponent and rely on the 519 // supercomponent resolution. 520 Optional<ResolvedBindings> bindingsPreviouslyResolvedInParent = 521 getPreviouslyResolvedBindings(bindingKey); 522 if (bindingsPreviouslyResolvedInParent.isPresent() 523 && !dependsOnLocalMultibindings(bindingsPreviouslyResolvedInParent.get())) { 524 return; 525 } 526 527 cycleStack.push(bindingKey); 528 try { 529 ResolvedBindings bindings = lookUpBindings(request); 530 for (Binding binding : bindings.ownedBindings()) { 531 for (DependencyRequest dependency : binding.implicitDependencies()) { 532 resolve(dependency); 533 } 534 } 535 resolvedBindings.put(bindingKey, bindings); 536 } finally { 537 cycleStack.pop(); 538 } 539 } 540 541 /** 542 * Returns {@code true} if {@code previouslyResolvedBindings} is multibindings with 543 * contributions declared within this (sub)component's modules, or if any of its unscoped 544 * provision-dependencies depend on such local multibindings. 545 * 546 * <p>We don't care about scoped dependencies or production bindings because they will never 547 * depend on multibindings with contributions from subcomponents. 548 */ 549 private boolean dependsOnLocalMultibindings(ResolvedBindings previouslyResolvedBindings) { 550 return dependsOnLocalMultibindings(previouslyResolvedBindings, new HashSet<BindingKey>()); 551 } 552 553 private boolean dependsOnLocalMultibindings( 554 final ResolvedBindings previouslyResolvedBindings, final Set<BindingKey> cycleChecker) { 555 // Don't recur infinitely if there are valid cycles in the dependency graph. 556 if (!cycleChecker.add(previouslyResolvedBindings.bindingKey())) { 557 return false; 558 } 559 try { 560 return dependsOnLocalMultibindingsCache.get( 561 previouslyResolvedBindings.bindingKey(), 562 new Callable<Boolean>() { 563 @Override 564 public Boolean call() { 565 if (previouslyResolvedBindings.isMultibindings() 566 && hasLocalContributions(previouslyResolvedBindings)) { 567 return true; 568 } 569 570 for (Binding binding : previouslyResolvedBindings.bindings()) { 571 if (!binding.scope().isPresent() 572 && !binding.bindingType().equals(Type.PRODUCTION)) { 573 for (DependencyRequest dependency : binding.implicitDependencies()) { 574 if (dependsOnLocalMultibindings( 575 getPreviouslyResolvedBindings(dependency.bindingKey()).get(), 576 cycleChecker)) { 577 return true; 578 } 579 } 580 } 581 } 582 return false; 583 } 584 }); 585 } catch (ExecutionException e) { 586 throw new AssertionError(e); 587 } 588 } 589 590 private boolean hasLocalContributions(ResolvedBindings resolvedBindings) { 591 return !explicitBindings.get(resolvedBindings.bindingKey().key()).isEmpty(); 592 } 593 594 ImmutableMap<BindingKey, ResolvedBindings> getResolvedBindings() { 595 ImmutableMap.Builder<BindingKey, ResolvedBindings> resolvedBindingsBuilder = 596 ImmutableMap.builder(); 597 resolvedBindingsBuilder.putAll(resolvedBindings); 598 if (parentResolver.isPresent()) { 599 Collection<ResolvedBindings> bindingsResolvedInParent = 600 Maps.difference(parentResolver.get().getResolvedBindings(), resolvedBindings) 601 .entriesOnlyOnLeft() 602 .values(); 603 for (ResolvedBindings resolvedInParent : bindingsResolvedInParent) { 604 resolvedBindingsBuilder.put( 605 resolvedInParent.bindingKey(), 606 resolvedInParent.asInheritedIn(componentDescriptor)); 607 } 608 } 609 return resolvedBindingsBuilder.build(); 610 } 611 612 ImmutableSet<ModuleDescriptor> getInheritedModules() { 613 return parentResolver.isPresent() 614 ? Sets.union( 615 parentResolver.get().getInheritedModules(), 616 parentResolver.get().componentDescriptor.transitiveModules()) 617 .immutableCopy() 618 : ImmutableSet.<ModuleDescriptor>of(); 619 } 620 621 ImmutableSet<ModuleDescriptor> getOwnedModules() { 622 return Sets.difference(componentDescriptor.transitiveModules(), getInheritedModules()) 623 .immutableCopy(); 624 } 625 } 626 } 627 } 628