0

I have some classes which require a specific object to be injected (lets name it ToInject). The problem is that I cannot provide ToInject from separate modules:

@Module(injects={OneActivity.class})
public class OneActivityModule {
    @Provides
    public ToInject provideToInject(){
        return new ToInject(...)
    }
}

@Module(injects={TwoActivity.class})
public class TwoActivityModule {
    @Provides
    public ToInject provideToInject(){
        return new ToInject(...)
    }
}

I get this exception when creating the ObjectGraph:

Caused by: java.lang.IllegalArgumentException: TwoActivityModule: Duplicate:
    com.example.test.OneActivityModule$$ModuleAdapter$ProvideToInjectProvidesAdapter[key=com.example.test.ToInject method=com.example.test.OneActivityModule.provideToInject()]
    com.example.test.TwoActivityModule$$ModuleAdapter$ProvideToInjectProvidesAdapter[key=com.example.test.ToInject method=com.example.test.TwoActivityModule.provideToInject()]
    at dagger.ObjectGraph$DaggerObjectGraph.makeGraph(ObjectGraph.java:187)
    at dagger.ObjectGraph$DaggerObjectGraph.access$000(ObjectGraph.java:138)
    at dagger.ObjectGraph.create(ObjectGraph.java:129)

I know that I could move ToInject providers to a single module, and use qualifiers to make then unique, but why can't I do it this way? injects is specified for each Module, ain't that makes those providers unique also?

Any suggestions?

UPDATE:

I thought about it, and the real problem is that I want to configure the ToInject object based on which Activity gets it. ToInject is actiually an abstract class (and the code snippet above uses a "not abstract" class just for the example).

My conclusion is that I should use only one provider for ToInject, so I can change the implementation with the change of a single line of code. But I would still need to configure the ToInject object based on which Activity get it.

So the main question became that whether this is possible with Dagger, or do I have to pass the configuration to every Activity, and manually set it?

The configuration in this case is an ID (String), and the object to configure (ToInject in this example) is a fragment that displays an advert banner. I want to separate it from the Activity as much as possible, so I can reuse it in other projects.

kupsef
  • 3,357
  • 1
  • 21
  • 31

1 Answers1

0

I found the sufficient solution.

This is a library responsible for providing the implementation of the abstract ToInject.

@Module(library=true)
public class ProviderModule {
    @Provides
    public ToInject provideToInject(){
        return new ToInjectConcrete1();
    }
}

And I can create Activity specific modules the way below. As you can see this ToInject provider method has a ToInject argument, that is actually provided by the library above. After I got it, I can do my further configuration that is specific to my Activity.

@Module(injects = OneActivity.class, includes = ProviderModule.class)
public class OneActivityModule {
    @Provides
    @Named("one")
    public ToInject provideToInject(ToInject toInject) {
        toInject.text = "overridden by one";

        return toInject;
    }
}

The key was the usage of qualifiers (in this case the @Named qualifier).

Note:

The origin of my problem was that I assumed provider methods in separate modules (with injects defined) are unique. Now I know that injects is for compile time verification, and has nothing to do with the uniquness of the providers. Providers with same return type can be made unique with qualifiers (for example @Named) just as how I did in this solution.

kupsef
  • 3,357
  • 1
  • 21
  • 31