Java – Dagger 2 cannot be provided without the @Provides-annotated method

Dagger 2 cannot be provided without the @Provides-annotated method… here is a solution to the problem.

Dagger 2 cannot be provided without the @Provides-annotated method

I

know there are a lot of similar problems, but I still can’t find a solution to the problem, and at this stage, I have no idea. I have the following settings:

  • Application modules/components: Used only for context and application objects.
  • Network modules/components: Retrofit clients
  • City module/component

  • : A module/component used to inject dependencies in the MVP screen. I want to inject Presenter and Interactor into the fragment.
  • PlaceRequests: Transform the interface

The code looks like this:

ApplicationModule.java

@Module
public class ApplicationModule {
    private Application mApp;

public ApplicationModule(Application app) {
        mApp = app;
    }

@Provides
    @Singleton
    public Application provideApplication() {
        return mApp;
    }

@Provides
    @Singleton
    Context provideApplicationContext() {
        return mApp.getApplicationContext();
    }
}

ApplicationComponent.java

@Singleton
@Component(modules = {ApplicationModule.class})
public interface ApplicationComponent {
    Application application();
    Context getContext();
}

NetModule.java

@Module
public class NetModule {

String mBaseUrl;

public NetModule(String baseUrl) {
        this.mBaseUrl = baseUrl;
    }

@Provides
    @Singleton
    SharedPreferences providesSharedPreferences(Application application) {
        return PreferenceManager.getDefaultSharedPreferences(application);
    }

@Provides
    @Singleton
    Cache provideOkHttpCache(Application application) {
        int cacheSize = 10 * 1024 * 1024;  10 MiB
        return new Cache(application.getCacheDir(), cacheSize);
    }

@Provides
    @Singleton
    OkHttpClient provideOkHttpClient(Cache cache) {
        OkHttpClient client = new OkHttpClient();
        client.setCache(cache);
        return client;
    }

@Provides
    @Singleton
    Retrofit provideRetrofit(OkHttpClient okHttpClient) {
        return new Retrofit.Builder()
                .addConverterFactory(JacksonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .baseUrl(mBaseUrl)
                .client(okHttpClient)
                .build();
    }

@Provides
    @Singleton
    PlaceRequests providePlaceRequests(Retrofit retrofit) {
        return retrofit.create(PlaceRequests.class);
    }
}

NetComponent.java

@Singleton
@Component(
        dependencies = {ApplicationModule.class},
        modules = {NetModule.class}
)
public interface NetComponent {
    Application application();
    PlaceRequests getPlaceRequests();
}

CityModule.java

@Module
public class CityModule {

private CityMvp.View view;

public CityModule(CityMvp.View view) {
        this.view = view;
    }

@Provides
    public CityMvp.View provideView() {
        return view;
    }

@Provides
    public CityMvp.Interactor provideInteractor(PlaceRequests placeRequests) {
        return new CityInteractor(placeRequests);
    }

@Provides
    public CityPresenter providePresenter(CityMvp.View cityView, CityMvp.Interactor interactor) {
        return new CityPresenter(cityView, interactor);
    }
}

CityComponent.java

@PerFragment
@Component(
        dependencies = {NetModule.class},
        modules = {CityModule.class}
)

public interface CityComponent {
    void inject(CityFragment cityFragment);
}

CityInteractor .java (unable to inject causes PlaceRequests dependency).

public class CityInteractor implements CityMvp.Interactor {

private PlaceRequests placeRequests;

public CityInteractor(PlaceRequests placeRequests) {
        this.placeRequests = placeRequests;
    }

@Override
    public void getPlaceDetails(String placeId, String key, Subscriber<PlaceDetails> subscriber) {
        Observable<PlaceDetails> observable = placeRequests.getPlaceDetails(placeId, key);
        observable.observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(Schedulers.io())
                .subscribe(subscriber);
    }
}

Finally, the error trajectory:

    : error: com.blabla.blabla.webapi.place.PlaceRequests cannot be provided without an @Provides-annotated method.
    void inject(CityFragment cityFragment);
         ^
      com.blabla.blabla.screens.city.CityFragment.presenter
          [injected field of type: com.blabla.blabla.screens.city.CityPresenter presenter]
      com.blabla.blabla.di.modules.CityModule.providePresenter(com.blabla.blabla.screens.city.CityMvp.View cityView, com.blabla.blabla.screens.city.CityMvp.Interactor interactor)
          [parameter: com.blabla.blabla.screens.city.CityMvp.Interactor interactor]
      com.blabla.blabla.di.modules.CityModule.provideInteractor(com.blabla.blabla.webapi.place.PlaceRequests placeRequests)
          [parameter: com.blabla.blabla.webapi.place.PlaceRequests placeRequests]
3 errors
:app:compileDebugJavaWithJavac FAILED

FAILURE: Build failed with an exception.

As far as I know, I expose the PlaceRequests object in NetComponent.java, and NetModule.java is a dependency of CityComponent. Why can’t I get the PlaceRequests dependency from CityComponent? What am I missing? Thanks!

Solution

Component dependencies Specifying by @Component(dependencies={...}) should not be modules because you own them. They should be types (usually components) that provide dependencies through zero-parameter methods called offering methods.

Switch your dependencies to components instead of modules.

If it helps, you may want to change the way you think about components, modules, and component dependencies. You can think of Dagger as creating object graphs where modules define the inputs or bindings (bind) of the graph, and components define the output or consumers of the graph. This makes component dependencies type or component inclusion or import from another external source, which may contain components created by different Daggers, but may not contain modules — rather than relying on modules that you will depend on the component that uses that module.

Related Problems and Solutions