Andrea Baccega
Andrea Baccega

Reputation: 27623

Dagger 2 Generic Type class inject error

I'm not able to let MyClass here being injected due to its Generic nature.

Dagger complains with this error:

Error:(187, 10) error: com.test.MyClass has type parameters, cannot members inject the raw type. via: com.test.MyComponent.inject(com.test.MyClass obj) [component injection method for type: com.test.MyClass]

I googled a bit but was unable to find a solution to this case scenario.

class MyClass<Type> {
    @Inject
    UserCredentials userCredentials;

    ResultProducer<Type> mRP;

    public MyClass(ResultProducer<Type> resultProd) {
        mRP = resultProd;
        Injector.getComponent().inject(this);
    }

    public Type getResult() {
        if (userCredentials.isLoggedIn()) {
            mRP.get();
        } else {
            mRP.getAnonymousCache();
        }
    }
}

@Component(modules = CredentialsModule.class )
interface MyComponent {
    void inject(MyClass obj);
}

@Module
class CredentialsModule {
    @Provides
    public UserCredentials provideUserCredentials() {
        return new UserCredentials();
    }
}

Upvotes: 41

Views: 24353

Answers (5)

Denis Solomko
Denis Solomko

Reputation: 1

You can use the next approach:

  1. Declare get* method in MainComponent.java
public interface MainComponent extends AndroidInjector<MainApplication> {
    
    @NonNull
    YourAwesomeClass getYourAwesomeClass();
}
  1. Save the link to the instance of the MainComponent in MainApplication.java
public class MainApplication extends AxisApplication {
    public static MainComponent mainComponent;

    @Override
    protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
        mainComponent = DaggerMainComponent
                .builder()
                .build();
        mainComponent.inject(this);

        return mainComponent;
    }
  1. Inject your class wherever you need in the app:
MyAwesomeClass myAwesomeClass = MainApplication.mainComponent.getYouAwesomeClass()

Upvotes: 0

Hylke
Hylke

Reputation: 705

I solved this issue a bit differently, like so (we're 5 years further, so its in Kotlin, but i guess Java would work too):

// The class I want to inject, multiple generics
class SomeDataStorage<K, V> {

  @Inject
  lateinit var theDependencyINeed: TheDependencyINeed

  init {
    ComponentSingleton.getSomeComponent().inject(this as SomeDataStorage<Any, Any>)
  }

  fun getValue(key: K): V {
    return theDependencyINeed.doSomeStuff() as V
  }
}

// Component
interface MyComponent {
  fun inject(someDataStorage: SomeDataStorage<Any, Any>)
}

The trick is to get some common parent of the generics you allow (in my case i dont care, so i just do Any, which is everything) and use that. Some unchecked casts are required, but thats OK.

Upvotes: 4

Leo DroidCoder
Leo DroidCoder

Reputation: 15046

For many will be useful to know, that it's allowed to inject fields into a generic class, without injecting the class itself.
It will be injected for you when a subclass is injected.
So you can have:

abstract class MyClass<? extends Something> {
    @Inject UserCredentials userCredentials;
    // you can use it further
}

class AnotherClass extends MyClass<Whatever> {
    // just inject this one
}

Upvotes: 11

alexshr
alexshr

Reputation: 1019

You can use dagger2 without "inject".

Add method to your component:

@Component(modules = CredentialsModule.class )
interface MyComponent {
void inject(MyClass obj);

UserCredentials getUserCredentials();
}

And use it without any problems:

userCredentials=Injector.getComponent().getUserCredentials();

But this approach can be inconvenient if you have a lot of fields to inject

Upvotes: 6

lobzik
lobzik

Reputation: 11064

I have run into the same issue and found this article.

In a nutshell you have this options:

  1. Make not generic wrapper class containing injected fields, make it to be a field of your class and inject it instead of generic class itself.
  2. Inject child non-generic class instead of base class. All annotated with @Inject fields of base class will be also injected, but they have to be public/protected that is not good.
  3. Make annotated with @Inject setter in the base class and private field. Injecting child non-generic class will lead to triggering the setter with parameter got from the object graph.

Upvotes: 53

Related Questions