Asked  7 Months ago    Answers:  5   Viewed   30 times

This is a Canonical Question because this is a common error with Dagger 2.

If your question was flagged as a duplicate please read this post carefully and make sure to understand what this error means and why it occured. If this post does not work for you make sure to include where and how you provide the mentioned classes and include the full error message in your question like the one here.

I tried to use a dependency with Dagger 2, but I receive the following error when I try to compile my project:

error: com.example.MyDependency cannot be provided without an @Inject constructor or from an @Provides-annotated method.

com.example.MyDependency is provided at
com.example.MyComponent.myDependency()

What does this mean and how can I fix it?

I have a component and tried to provide a dependency. My basic setup looks like this:

// this is the dependency I try to use
class MyDependency {}

@Component
interface MyComponent {
    // I want to make it accessible to be used with my component
    MyDependency myDependency();
}

 Answers

65

tl;dr You forgot to either add an @Inject to your constructor so that Dagger can use Constructor Injection to provide the object, or you need some method in one of your Modules that creates or binds the object.


What's going on?

Have a good look at the error message: It states that you try to request a dependency but Dagger has no way to provide or create it. It simply does not know how to, because it cannot be provided without an @Inject constructor or from an @Provides-annotated method.

A close look at the error message shows the class (a) that you are trying to provide and the component (b) that needs it.

com.example.MyDependency (a) is provided at
com.example.MyComponent.myDependency() (b)

You have to make sure that (b) can create or provide (a) to fix your issue.

It looks a bit more complex if you tried to inject your dependency somewhere else, but you can still see the full stack of events—in this case a constructor injection missing a dependency. The class (a) that you are trying to provide and the location (b) where Dagger tried injecting it. It also tells you where that dependent class was created (c) and again the component (d) that failed providing (a).

com.example.MyDependency cannot be provided without an @Inject constructor or from an @Provides-annotated method.
com.example.MyDependency (a) is injected at
com.example.DependentClass.(dependency) (b)
com.example.DependentClass is provided at (c)
com.example.MyComponent.myDependency() (d)

The same applies here: Make sure that (d) knows how to provide (a) and you're good to go.

How do I fix this?

Have a look at the error as shown above. Make sure you understand where it occured and what you are trying to inject. Then tell Dagger how to provide your object.

an @Inject constructor

As the error states, you try to use MyDependency but MyComponent does not know how to do that. If we have a look at the example it becomes clear why:

class MyDependency {}

The class has no @Inject annotated constructor! And there is no other module in the component, so there is nothing Dagger could do.

If you want to use constructor injection you can just add an @Inject annotated constructor and are done. Dagger will see this constructor and know how to create your class.

class MyDependency {
    @Inject
    MyDependency() { /**/ }
}

That is all you have to do when you can make use of constructor injection.

from an @Provides-annotated method

The error message states a second option, which allows you to provide an object if you don't want—or can't—use constructor injection. You can also add a @Provides annotated method to a module and add this module to your component.

@Module
class MyModule {
    @Provides
    MyDependency provideMyDependency() {
        return new MyDependency();
    }
}

@Component(modules = MyModule.class)
interface MyComponent {
    MyDependency myDependency();
}

This way Dagger can use your module to create and provide your dependency. It is a little bit more boilerplate than using Constructor Injection, but you will have to use Modules for everything that needs further setup or that does not have an annotated constructor, e.g. third party libraries like Retrofit, OkHttp, or Gson.


There are also other ways to provide a dependency from a component. A @SubComponent has access to its parents dependencies, and a component dependency can expose some of its dependencies to its dependent components. But at some point everything Dagger provides needs to either have an @Inject constructor or a Module providing it.

But I did add MyDependency!

Pay close attention to the details. You probably are using an interface when you are only providing the implementation, or try to use a parent class when Dagger only knows about the subclass.
Maybe you added a custom @Qualifier or used @Named("typeA") with it. To Dagger this is a completely different object! Double check that you actually provide and request the same dependency.

Read the error and make sure that you either have an @Inject annotated constructor, a module that has a @Provides method that provides that type, or a parent component that does.

What if I want to provide an implementation for my interface?

A simple example like the following shows how one class extends another:

class MyDependency extends MyBaseDependency {
    @Inject MyDependency() { super(); }
}

This will inform Dagger about MyDependency, but not about MyBaseDependency.

If you have one class implementing an interface or extending a super class you have to declare that. If you provide MyDependency this does not mean that Dagger can provide MyBaseDependency. You can use @Binds to tell Dagger about your implementation and provide it when the super class is required.

@Module
interface MyModule {
    @Binds
    MyBaseDependency provideMyBaseDependency(MyDependency implementation);
}
Tuesday, June 1, 2021
 
Jubair
answered 7 Months ago
92

After digging a little bit more I found the issue. It's completely un-related to the code I'm using. It regards Kotlin 1.3.30.

Here some more information about it.

Downgrading to Kotlin 1.3.21 resolved the problem.

Wednesday, July 7, 2021
 
MannfromReno
answered 5 Months ago
22

You're making a mistake in that you are using

DaggerBootstrap.create().initialize(this);

in your Activity, as scopes are not shared across multiple component instances. What I recommend is using a custom application class

public class CustomApplication extends Application {
    @Override
    public void onCreate() {
         super.onCreate();
         Bootstrap.INSTANCE.setup();
    }
}

@Component
@Singleton
public interface _Bootstrap {
    void initialize(ActivityA activityA);
    //void initiali...
}

public enum Bootstrap {
    INSTANCE;

    private _Bootstrap bootstrap;

    void setup() {
        bootstrap = Dagger_Bootstrap.create();
    }

    public _Bootstrap getBootstrap() {
        return bootstrap;
    }
}

Then you could call it as

Bootstrap.INSTANCE.getBootstrap().initialize(this);

This way, you share the component across your classes. I personally named Bootstrap as injector, and _Bootstrap as ApplicationComponent, so it looks like this:

Injector.INSTANCE.getApplicationComponent().inject(this);

But that's just my typical setup. Names don't really matter.

EDIT: To your last question, you can solve this by subscoping and component dependencies.

Your library project should be able to see only the library classes, correct? In that case, all you do is

@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface LibraryScope {
}

@Component(modules={LibraryModule.class})
@LibraryScope
public interface LibraryComponent {
    LibraryClass libraryClass(); //provision method for `MyManager`
}

@Module
public class LibraryModule {
    @LibraryScope
    @Provides
    public LibraryClass libraryClass() { //in your example, LibraryClass is `MyManager`
        return new LibraryClass(); //this is instantiation of `MyManager`
    }
}

public enum LibraryBootstrap {
    INSTANCE;

    private LibraryComponent libraryComponent;

    static {
        INSTANCE.libraryComponent = DaggerLibraryComponent.create();
    }

    public LibraryComponent getLibraryComponent() {
        return libraryComponent;
    }
}

@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface ApplicationScope {
}

@Component(dependencies={LibraryComponent.class}, modules={AdditionalAppModule.class})
@ApplicationScope
public interface ApplicationComponent extends LibraryComponent {
    AdditionalAppClass additionalAppClass();

    void inject(InjectableAppClass1 injectableAppClass1);
    void inject(InjectableAppClass2 injectableAppClass2);
    void inject(InjectableAppClass3 injectableAppClass3);
}

@Module
public class AdditionalAppModule {
    @ApplicationScope
    @Provides
    public AdditionalAppClass additionalAppClass() { //something your app shares as a dependency, and not the library
        return new AdditionalAppClass();
    }
}

public enum ApplicationBootstrap {
    INSTANCE;

    private ApplicationComponent applicationComponent;

    void setup() {
        this.applicationComponent = DaggerApplicationComponent.builder()
                                        .libraryComponent(LibraryBootstrap.INSTANCE.getLibraryComponent())
                                        .build();
    }

    public ApplicationComponent getApplicationComponent() {
        return applicationComponent;
    }
}

Then

@Inject
LibraryClass libraryClass; //MyManager myManager;

...
    ApplicationBootstrap.INSTANCE.getApplicationComponent().inject(this);
Tuesday, July 20, 2021
 
sassy_geekette
answered 5 Months ago
73

I recently post the answer to a question like this in this post :

Dagger 2 : error while getting a multiple instances of same object with @Named

You need to use @Named("someName")in your module like this:

@Module
public class ApplicationModule {
private Shape rec;
private Shape circle;

public ApplicationModule() {
    rec = new Rectangle();
    circle= new Circle ();
}

@Provides
 @Named("rect")
public Shape provideRectangle() {
    return rec ;
}

@Provides
 @Named("circle")
public Shape provideCircle() {
    return circle;
}

}

Then wherever you need to inject them just write

@Inject
@Named("rect")
 Shape objRect;

its funny but you have to inject in a different way in Kotlin:

@field:[Inject Named("rect")]
lateinit var objRect: Shape
Sunday, August 8, 2021
 
Shawson
answered 4 Months ago
68

Seems like I've figured out what was wrong with my Dagger 2 setup. It's not possible to use the same scope in both component and subcomponents. It's required to define a new scope for subcomponent. In my case I've ended up creating @Screen scope for me subcomponent.

I'd say that this is a small but very annoying defect in Dagger 2. Apparently dagger-compiler reports nice and understandable error about the same scopes in a parent component and child component if child component is extended with a parent component as dependency. But completely misleading error is reported by the compiler if parent component and child subcomponent share the same scope.

Thank you, @lukas, for giving me a hint here https://stackoverflow.com/a/30383088/808313 that led to a problem resolution.

Wednesday, August 11, 2021
 
swydell
answered 4 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :  
Share