Alexey
Alexey

Reputation: 3192

dagger 2 'can not be provided without'

To simplify problem prerequisites suppose the following sources set:

src/main/java/di

ApplicationComponent.java:

@PerApplication
@Component(modules = {ApplicationModule.class})
public interface ApplicationComponent {
    void inject(MyApplication target);
}

ApplicationModule.java

@Module
public class ApplicationModule {
    @Provides @PerApplication
    CoffeeMaker provideCoffeeMaker(CoffeeMakerImpl impl) { return impl; }
}

src/debug/java/di

DebugApplicationComponent.java:

@PerApplication
@Component(modules = {DebugApplicationModule.class})
public interface DebugApplicationComponent extends ApplicationComponent {}

DebugApplicationModule.java

@Module(includes = ApplicationModule.class)
public class DebugApplicationModule {
    @Provides @PerApplication
    Heater provideHeater(HeaterImpl impl) { return impl; }
}

src/main/java/app

CoffeeMakerImpl.java

class CoffeeMakerImpl implements CoffeeMaker {
    @Inject CoffeeMakerImpl(Heater heater) {}
}

In MyApplication.java

@Inject CoffeeMaker coffeeMaker;

DaggerDebugApplicationComponent.
    builder().
    applicationModule(new ApplicationModule(application)).
    debugApplicationModule(new DebugApplicationModule()).
    build().
    inject(this);

When compiling the project I got error:

Error:(18, 10) error: Heater cannot be provided without an @Provides-annotated method.
app.Heater is injected at
app.CofeeMakerImpl.<init>(heater)
app.CofeeMakerImpl is injected at
app.MyApplication
app.MyApplication is injected at
di.ApplicationComponent.inject(target)

I expect, that due DebugApplicationModule includes ApplicationModule, and I pass to DebugApplicationComponent both of these modules, DebugApplicationComponent, should see both Heater and CoffeeMaker.

What could be a reason, why Heater is not accessible in injection chain?

P.S. Thanks to @DavidMedenjak, solution is quite simple: just make ApplicationComponent a plain interface, removing @PerApplication @Component(modules = {ApplicationModule.class}) line.

See his answer, there are some useful advices there.

Upvotes: 0

Views: 60

Answers (1)

David Medenjak
David Medenjak

Reputation: 34532

I expect, that due DebugApplicationModule includes ApplicationModule [...] should see both Heater and CoffeeMaker.

DebugApplicationModule compiles fine, the problem is that your ApplicationComponent cannot compile, since it does not know how to inject MyApplication.

@PerApplication
@Component(modules = {ApplicationModule.class})
public interface ApplicationComponent {
  void inject(MyApplication target);
}

Here you declare that this component knows how to inject MyApplication, but it has no access or knowledge about Heater, as you can see in the compile error:

error:(18, 10) error: Heater cannot be provided without an @Provides-annotated method.
app.Heater is injected at
app.CofeeMakerImpl.<init>(heater)
app.CofeeMakerImpl is injected at
app.MyApplication
app.MyApplication is injected at  <- trying to inject MyApplication
di.ApplicationComponent.inject(target) <- ApplicationComponent has the problem

Make sure to always look very closely at the compile errors. You only add this knowledget to your DebugApplicationModule, but ApplicationComponent also says it can inject the class, which it can't.


To solve this the obvious solutions would be to remove the inject() signature from your ApplicationComponent and move it to your DebugApplicationComponent, since it just doesn't know how to inject it. The full information to inject your Application is within your DebugApplicationComponent, and later maybe also ReleaseApplicationComponent.

Since you probably want an interface that your components implement, you could also just remove the @Component annotation from ApplicationComponent.

public interface ApplicationComponent {
  void inject(MyApplication target);
}

Make it a plain interface, and Dagger will not try to generate an implementation.

You could also have a look at component builder methods, where you could bind / add different objects / modules to a component.

Upvotes: 1

Related Questions