Reputation: 3192
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
Reputation: 34532
I expect, that due
DebugApplicationModule
includesApplicationModule
[...] should see bothHeater
andCoffeeMaker
.
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