17

I am trying to make Dagger work without the "injects" directive inside the @Module annotation. I am basing my test project on the Android Simple Dagger example

This is the part that is giving me problems:

@Module(
    injects = HomeActivity.class,
    complete = false
)
public class DemoModule {
  // TODO put your application-specific providers here!
}

(Edit): Which in my code is CTXModules.java

The part that I'd like to remove is the "injects = HomeActivity.class". I know I can mark my own modules with the @Inject annotation in the constructor to remove that part there, but somehow it doesn't work with the module that is added to the graph. With that line there, everything works just fine.

The reason I need this is because dagger will be implemented in a base-library project that will be the foundation for some projects that share a common code base and therefore at the moment or writing the this part of the code I don't know what classes will inject modules.

Is what I am trying to do even possible?

I assume it is possible because the Android Module class does not use that directive.

Hope it's clear enough. Thanks in advance!

(EDIT)

I should have mentioned it. In my module I remove "injects = HomeActivity.class" and add "library = true" like in the Android Module class. What happens then is that I get this error (my bad I not added it before):

12-10 09:21:16.807: E/AndroidRuntime(21783): FATAL EXCEPTION: main
12-10 09:21:16.807: E/AndroidRuntime(21783): Process: com.ef.daggertestproject, PID: 21783
12-10 09:21:16.807: E/AndroidRuntime(21783): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.ef.daggertestproject/com.ef.daggertestproject.MainActivity}: java.lang.IllegalArgumentException: No inject registered for members/com.ef.daggertestproject.MainActivity. You must explicitly add it to the 'injects' option in one of your modules.
12-10 09:21:16.807: E/AndroidRuntime(21783):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2176)
12-10 09:21:16.807: E/AndroidRuntime(21783):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2226)
12-10 09:21:16.807: E/AndroidRuntime(21783):    at android.app.ActivityThread.access$700(ActivityThread.java:135)
12-10 09:21:16.807: E/AndroidRuntime(21783):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1397)
12-10 09:21:16.807: E/AndroidRuntime(21783):    at android.os.Handler.dispatchMessage(Handler.java:102)
12-10 09:21:16.807: E/AndroidRuntime(21783):    at android.os.Looper.loop(Looper.java:137)
12-10 09:21:16.807: E/AndroidRuntime(21783):    at android.app.ActivityThread.main(ActivityThread.java:4998)
12-10 09:21:16.807: E/AndroidRuntime(21783):    at java.lang.reflect.Method.invokeNative(Native Method)
12-10 09:21:16.807: E/AndroidRuntime(21783):    at java.lang.reflect.Method.invoke(Method.java:515)
12-10 09:21:16.807: E/AndroidRuntime(21783):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:777)
12-10 09:21:16.807: E/AndroidRuntime(21783):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:593)
12-10 09:21:16.807: E/AndroidRuntime(21783):    at dalvik.system.NativeStart.main(Native Method)
12-10 09:21:16.807: E/AndroidRuntime(21783): Caused by: java.lang.IllegalArgumentException: No inject registered for members/com.ef.daggertestproject.MainActivity. You must explicitly add it to the 'injects' option in one of your modules.
12-10 09:21:16.807: E/AndroidRuntime(21783):    at dagger.ObjectGraph$DaggerObjectGraph.getInjectableTypeBinding(ObjectGraph.java:281)
12-10 09:21:16.807: E/AndroidRuntime(21783):    at dagger.ObjectGraph$DaggerObjectGraph.inject(ObjectGraph.java:258)
12-10 09:21:16.807: E/AndroidRuntime(21783):    at com.ef.daggertestproject.MyApplication.inject(MyApplication.java:47)
12-10 09:21:16.807: E/AndroidRuntime(21783):    at com.ef.daggertestproject.BaseActivity.onCreate(BaseActivity.java:27)
12-10 09:21:16.807: E/AndroidRuntime(21783):    at com.ef.daggertestproject.MainActivity.onCreate(MainActivity.java:16)
12-10 09:21:16.807: E/AndroidRuntime(21783):    at android.app.Activity.performCreate(Activity.java:5243)
12-10 09:21:16.807: E/AndroidRuntime(21783):    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
12-10 09:21:16.807: E/AndroidRuntime(21783):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2140)
12-10 09:21:16.807: E/AndroidRuntime(21783):    ... 11 more

Also, I've uploaded my test project to github

(Final Edit) according to Jake's answer: "Declaring a module as a library does not alleviate the needs of Dagger to know about injection points." And therefore the answer to my original question is that it's not possible.

spCoder
  • 318
  • 2
  • 9

1 Answers1

24

You want

@Module(library=true)

Here's what the docs say about library:

False if all the included bindings in this module are necessary to satisfy all of its injectable types. If a module is not a library module, it is eligible for additional static checking: tools can detect if included bindings are not necessary. If you provide bindings that are not used by this module's graph, then you must declare library = true.

(emphasis mine)


Declaring a module as a library does not alleviate the needs of Dagger to know about injection points. You still must declare a module in the object graph with the listed injects.

An extreme simplified version of your example would look like this:

repo/
 +- library/
 |   +- Foo.java
 |   `- FooModule.java
 |
 `- app/
     +- BarActivity.java
     `- BarModule.java

FooModule.java:

@Module(library = true)
public final class FooModule {
  @Provides @Singleton provideFoo() {
    return Foo();
  }
}

BarModule.java:

@Module(
  injects = BarActivity.class,
  includes = FooModule.class
)
public final class BarModule {
}

In BarActivity.java (or similar):

ObjectGraph og = ObjectGraph.create(new BarModule());
og.inject(this);
Jake Wharton
  • 75,598
  • 23
  • 223
  • 230
  • Thanks Jake, I already tried that and still doesn't work. My bad I didn't specify it. I've edited my question with more relevant information and also I've added my test project to github and some links to the classes I mentioned. – spCoder Dec 10 '13 at 09:38
  • 1
    I've updated my answer to show downstream consumption of a library module. You still need to tell Dagger about `injects` somewhere in order be able to inject. – Jake Wharton Dec 10 '13 at 21:51
  • 2
    So as you specified at the start of your edit: "Declaring a module as a library does not alleviate the needs of Dagger to know about injection points." And therefore the answer to my original question is that it's not possible. Thanks Jake! – spCoder Dec 11 '13 at 14:52
  • 2
    I would like to know what happens if for example you declare a module and a (inject = BaseActivity.class) and then in the BaseActivity you call App.inject(this); and then subclass BaseActivity. since BaseActivity is the only class needing injection, why is it still telling me I need to declare the subclass in the (injects = ...) parameter? – superjugy Feb 12 '14 at 03:38
  • @superjugy Doesn't work because `this != BaseActivity.class` when run. – Jake Wharton Feb 12 '14 at 03:40
  • So I would have to declare an empty module just to add this subclasses? For example: @Module(injects = MySubClass.class, includes = BaseModule.class) public class MyModule { } and also add it to the graph like protected Object[] getModulesList() { return new Object[]{new BaseModule(), new MyModule()}; } – superjugy Feb 12 '14 at 04:18
  • 1
    All injection points must be listed in a module. So, yes. Something along those lines. – Jake Wharton Feb 12 '14 at 04:29
  • 5
    So just about every class in my app needs to be in this list. Seems silly. – miguel Feb 26 '14 at 02:46
  • 5
    @miguel Welcome to static analysis at compile-time instead of runtime. We're working on this for 2.0 but what do you expect when we need to know about the entire graph without running the app. – Jake Wharton Feb 26 '14 at 02:48
  • @JakeWharton It is definitely a bit of shift in thinking coming from runtime DI frameworks. Still glad we have this option for Android! – Jedidja Oct 31 '14 at 08:44