11

I am trying to understand Components in Dagger 2. Here is an example:

@Component(modules = { MyModule.class })
public interface MyComponent {

    void inject(InjectionSite injectionSite);

    Foo foo();

    Bar bar();   

}

I understand what the void inject() methods do. But I don't understand what the other Foo foo() getter methods do. What is the purpose of these other methods?

David Rawson
  • 20,912
  • 7
  • 88
  • 124
  • Related: an explanation of the difference between the components and modules http://stackoverflow.com/a/42616757/5241933 – David Rawson Mar 15 '17 at 09:40

2 Answers2

13

Usage in dependent components

In the context of a hierarchy of dependent components, such as in this example, provision methods such as Foo foo() are for exposing bindings to a dependent component. "Expose" means "make available" or even "publish". Note that the name of the method itself is actually irrelevant. Some programmers choose to name these methods Foo exposeFoo() to make the method name reflect its purpose.

Explanation:

When you write a component in Dagger 2, you group together modules containing @Provides methods. These @Provides methods can be thought of as "bindings" in that they associate an abstraction (e.g., a type) with a concrete way of resolving that type. With that in mind, the Foo foo() methods make the Component able to expose its binding for Foo to dependent components.

Example:

Let's say Foo is an application Singleton and we want to use it as a dependency for instances of DependsOnFoo but inside a component with narrower scope. If we write a naive @Provides method inside one of the modules of MyDependentComponent then we will get a new instance. Instead, we can write this:

@PerFragment
@Component(dependencies = {MyComponent.class }
           modules = { MyDependentModule.class })
public class MyDependentComponent {

    void inject(MyFragment frag);

}

And the module:

@Module
public class MyDepedentModule {

    @Provides
    @PerFragment
    DependsOnFoo dependsOnFoo(Foo foo) {
        return new DependsOnFoo(foo);
    }
}

Assume also that the injection site for DependentComponent contains DependsOnFoo:

public class MyFragment extends Fragment {
    
    @Inject DependsOnFoo dependsOnFoo

}

Note that MyDependentComponent only knows about the module MyDependentModule. Through that module, it knows it can provide DependsOnFoo using an instance of Foo, but it doesn't know how to provide Foo by itself. This happens despite MyDependentComponent being a dependent component of MyComponent. The Foo foo() method in MyComponent allows the dependent component MyDependentComponent to use MyComponent's binding for Foo to inject DependsOnFoo. Without this Foo foo() method, the compilation will fail.

Usage to resolve a binding

Let's say we would like to obtain instances of Foo without having to call inject(this). The Foo foo() method inside the component will allow this much the same way you can call getInstance() with Guice's Injector or Castle Windsor's Resolve. The illustration is as below:

public void fooConsumer() {
    DaggerMyComponent component = DaggerMyComponent.builder.build();
    Foo foo = component.foo();
}
Community
  • 1
  • 1
David Rawson
  • 20,912
  • 7
  • 88
  • 124
  • Ok, I think I might be getting this... I correctly understand your *Example 2* and up to this point I thought this was the only usage for bindings. As for *Example 1* and why my code was still compiling without the bindings... First, I'm using subcomponents instead of component dependencies. And second, I never had anything like `@Provides DependsOnFoo dependsOnFoo(Foo foo) { return new DependsOnFoo(foo); }` on my code. I never saw that in your answer to my question nor I inferred that somehow. Hopefully what I ended up with has nothing wrong with it. – rfgamaral Jan 04 '17 at 20:53
  • I think I know understand this a little better and the reason that my code (as shown [http://stackoverflow.com/questions/41444511/trying-to-get-my-head-around-dependency-injection-on-android-with-dagger2](here)) based on your answer worked just fine is maybe because I'm using subcomponents instead of component dependencies? That's the only explanation, but I'm no Dagger expert... – rfgamaral Jan 04 '17 at 21:02
  • 1
    @Ricardo yes that sounds right - subcomponents work differently. I guess we ended up talking at cross-purposes because my answer was using dependent components. If you had used my answer to that question as-is then you would need to publish `OkHttpClient` because it was being used as a dependency in the dependent component. – David Rawson Jan 04 '17 at 21:35
  • Glad we could sort everything out. Thanks a lot. You really helped me understand Dagger a bit more :) – rfgamaral Jan 04 '17 at 22:53
9

Dagger is a way of wiring up graphs of objects and their dependencies. As an alternative to calling constructors directly, you obtain instances by requesting them from Dagger, or by supplying an object that you'd like to have injected with Dagger-created instances.

Let's make a coffee shop, that depends on a Provider<Coffee> and a CashRegister. Assume that you have those wired up within a module (maybe to LightRoastCoffee and DefaultCashRegister implementations).

public class CoffeeShop {
  private final Provider<Coffee> coffeeProvider;
  private final CashRegister register;

  @Inject
  public CoffeeShop(Provider<Coffee> coffeeProvider, CashRegister register) {
    this.coffeeProvider = coffeeProvider;
    this.register = register;
  }

  public void serve(Person person) {
    cashRegister.takeMoneyFrom(person);
    person.accept(coffeeProvider.get());
  }
}

Now you need to get an instance of that CoffeeShop, but it only has a two-parameter constructor with its dependencies. So how do you do that? Simple: You tell Dagger to make a factory method available on the Component instance it generates.

@Component(modules = {/* ... */})
public interface CoffeeShopComponent {
  CoffeeShop getCoffeeShop();

  void inject(CoffeeService serviceToInject); // to be discussed below
}

When you call getCoffeeShop, Dagger creates the Provider<Coffee> to supply LightRoastCoffee, creates the DefaultCashRegister, supplies them to the Coffeeshop constructor, and returns you the result. Congratulations, you are the proud owner of a fully-wired-up coffeeshop.

Now, all of this is an alternative to void injection methods, which take an already-created instance and inject into it:

public class CoffeeService extends SomeFrameworkService {
  @Inject CoffeeShop coffeeShop;

  @Override public void initialize() {
    // Before injection, your coffeeShop field is null.
    DaggerCoffeeShopComponent.create().inject(this);
    // Dagger inspects CoffeeService at compile time, so at runtime it can reach
    // in and set the fields.
  }

  @Override public void alternativeInitialize() {
    // The above is equivalent to this, though:
    coffeeShop = DaggerCoffeeShopComponent.create().getCoffeeShop();
  }
}

So, there you have it: Two different styles, both of which give you access to fully-injected graphs of objects without listing or caring about exactly which dependencies they need. You can prefer one or the other, or prefer factory methods for the top-level and members injection for Android or Service use-cases, or any other sort of mix and match.

(Note: Beyond their use as entry points into your object graph, no-arg getters known as provision methods are also useful for exposing bindings for component dependencies, as David Rawson describes in the other answer.)

Community
  • 1
  • 1
Jeff Bowman
  • 90,959
  • 16
  • 217
  • 251
  • Thanks for your answer. I'll delete mine if you think it's wrong or misleading. I have been thinking for a while about how to express these ideas in Dagger 2 and to me it "feels" right to talk about publishing bindings with components in Dagger 2 even though this is normally something you would associate with modules. It seems like components in Dagger 2 are a halfway between an Injector and a Module and so many of the points that apply to modules can apply to components as well. I couldn't find a canonical source to refer to so I had a go at an answer. – David Rawson Jan 04 '17 at 23:35
  • 1
    @DavidRawson I wouldn't say yours is worth deleting; there are multiple ways to approach the same concept that speak to different people with different backgrounds. To me, though, the "publication" aspect only applies to component dependencies, as all Component methods have a 1-to-1 mapping with a method on a Guice Injector (`injectMembers` for `void` methods, `getInstance`/`getProvider` for factory methods, `createChildInjector` for subcomponents, etc) and like with Guice you can rely on injecting objects like `MembersInjector` or `Provider` without "publishing" them. – Jeff Bowman Jan 05 '17 at 00:57
  • Thanks - the point about relying on injection of an object without "publishing" the binding is apposite. I didn't think of that. I'm going to read a bit more and then edit my answer. – David Rawson Jan 05 '17 at 01:14