Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optional bindings in a parent component can sometimes use bindings from child components #4239

Open
goj opened this issue Feb 8, 2024 · 2 comments

Comments

@goj
Copy link

goj commented Feb 8, 2024

Like #2085, but for optional bindings.

It's possible for a child component to satisfy an optional binding, so that it will be injected into a parent component's class.

Example: https://gist.github.com/goj/defb14a6232064a0a4beb7d77913e8c3

Is it a bug or a feature?

It's a bug. Adding a scoping annotations (e.g. making JudgmentalCoffee a @Singleton in the example above) changes what gets injected. For a big projects and long injection chains this may lead to a very surprising results.

@bcorso
Copy link

bcorso commented Feb 8, 2024

Hi @goj,

This particular case is actually working as intended.

Note that the feature only works for bindings that depend on optional bindings and/or multibindings. In particular, Dagger will re-resolve a binding in a component if there is a contribution to the optional binding or multibinding in that component.

For example, with multibindings you can have something like this:

@Module
interface ParentModule {
  @Multibinds
  Set<Bar> setOfBar();

  @Provides
  Foo provideFoo(Set<Bar> setOfBar) { ... }
}

@Module
interface ChildModule {
  @Provides
  @IntoSet
  Bar provideBarIntoSet() { ... }
}

public void main() {
  // The set is empty in this Foo
  Foo parentFoo = parentComponent.getFoo();

  // The set has one element in this Foo
  Foo childFoo = childComponent.getFoo();
}

I do agree that the behavior is a bit confusing since the contents of the optional or multibinding can change depending on which component you request it from, but that's how they were designed and also their main benefit.

Also note that #2085 is different and that actually is a bug. In that case the issue was that we were re-resolving for non-optional/multibindings.

@bcorso
Copy link

bcorso commented Feb 8, 2024

It's a bug. Adding a scoping annotations (e.g. making JudgmentalCoffee a @Singleton in the example above) changes what gets injected. For a big projects and long injection chains this may lead to a very surprising results

Sorry, forgot to comment on this in my previous post.

Yes, scoping JudgmentalCoffee with @Singleton means that it will be locked into the ParentComponent and so it would no longer pick of the Sugar you've provided in your ChildComponent (i.e. the Optional<Sugar> it injects will be empty).

This complexity is part of the trade-off of using optional/multibindings, and I would advise to use them as little as possible and only when absolutely needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants